summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/Certificate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceSSL/Certificate.cpp')
-rwxr-xr-xcpp/src/IceSSL/Certificate.cpp2076
1 files changed, 0 insertions, 2076 deletions
diff --git a/cpp/src/IceSSL/Certificate.cpp b/cpp/src/IceSSL/Certificate.cpp
deleted file mode 100755
index a5808186d97..00000000000
--- a/cpp/src/IceSSL/Certificate.cpp
+++ /dev/null
@@ -1,2076 +0,0 @@
-// **********************************************************************
-//
-// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
-//
-// This copy of Ice is licensed to you under the terms described in the
-// ICE_LICENSE file included in this distribution.
-//
-// **********************************************************************
-
-#include <IceUtil/DisableWarnings.h>
-#include <IceUtil/Mutex.h>
-#include <IceUtil/MutexPtrLock.h>
-#include <IceUtil/StringUtil.h>
-#include <IceSSL/Plugin.h>
-#include <IceSSL/Util.h>
-#include <IceSSL/RFC2253.h>
-#include <Ice/Object.h>
-#include <Ice/Base64.h>
-#include <Ice/StringConverter.h>
-#include <IceUtil/Time.h>
-
-#if defined(ICE_USE_OPENSSL)
-# include <openssl/x509v3.h>
-# include <openssl/pem.h>
-//
-// Avoid old style cast warnings from OpenSSL macros
-//
-# pragma GCC diagnostic ignored "-Wold-style-cast"
-#elif defined(ICE_USE_SECURE_TRANSPORT)
-# include <Security/Security.h>
-#elif defined(ICE_OS_UWP)
-# include <ppltasks.h>
-# include <nserror.h>
-#endif
-
-#ifdef __SUNPRO_CC
-
-//
-// The call to sk_GENERAL_NAME_pop_free fails to compile if we don't
-// remove the extern "C" vs non extern "C" check with the macro below:
-//
-
-extern "C" typedef void (*FreeFunc)(void*);
-
-#undef CHECKED_SK_FREE_FUNC
-#define CHECKED_SK_FREE_FUNC(type, p) \
- (FreeFunc) (p)
-
-#endif
-
-using namespace std;
-using namespace Ice;
-using namespace IceInternal;
-using namespace IceSSL;
-
-#ifdef ICE_OS_UWP
-using namespace concurrency;
-using namespace Platform;
-using namespace Windows::Foundation;
-using namespace Windows::Storage;
-using namespace Windows::Storage::Streams;
-using namespace Windows::Security::Cryptography;
-#endif
-
-#if defined(ICE_USE_SECURE_TRANSPORT) || defined(ICE_USE_SCHANNEL)
-
-//
-// Map a certificate OID to its alias
-//
-struct CertificateOID
-{
- const char* name;
- const char* alias;
-};
-
-const CertificateOID certificateOIDS[] =
-{
- {"2.5.4.3", "CN"},
- {"2.5.4.4", "SN"},
- {"2.5.4.5", "DeviceSerialNumber"},
- {"2.5.4.6", "C"},
- {"2.5.4.7", "L"},
- {"2.5.4.8", "ST"},
- {"2.5.4.9", "STREET"},
- {"2.5.4.10", "O"},
- {"2.5.4.11", "OU"},
- {"2.5.4.12", "T"},
- {"2.5.4.42", "G"},
- {"2.5.4.43", "I"},
- {"1.2.840.113549.1.9.8", "unstructuredAddress"},
- {"1.2.840.113549.1.9.2", "unstructuredName"},
- {"1.2.840.113549.1.9.1", "emailAddress"},
- {"0.9.2342.19200300.100.1.25", "DC"}
-};
-const int certificateOIDSSize = sizeof(certificateOIDS) / sizeof(CertificateOID);
-
-#endif
-
-#if defined(ICE_USE_SECURE_TRANSPORT)
-
-string
-certificateOIDAlias(const string& name)
-{
- for(int i = 0; i < certificateOIDSSize; ++i)
- {
- const CertificateOID* certificateOID = &certificateOIDS[i];
- assert(certificateOID);
- if(name == certificateOID->name)
- {
- return certificateOID->alias;
- }
- }
- return name;
-}
-
-string
-escapeX509Name(const string& name)
-{
- ostringstream os;
- for(string::const_iterator i = name.begin(); i != name.end(); ++i)
- {
- switch(*i)
- {
- case ',':
- case '=':
- case '+':
- case '<':
- case '>':
- case '#':
- case ';':
- {
- os << '\\';
- }
- default:
- {
- break;
- }
- }
- os << *i;
- }
- return os.str();
-}
-
-#if !defined(ICE_USE_SECURE_TRANSPORT_IOS)
-
-//
-// Map alternative name alias to its types.
-//
-const char* certificateAlternativeNameTypes[] = {"", "Email Address", "DNS Name", "", "Directory Name", "", "URI",
- "IP Address"};
-const int certificateAlternativeNameTypesSize = sizeof(certificateAlternativeNameTypes) / sizeof(char*);
-
-int
-certificateAlternativeNameType(const string& alias)
-{
- if(!alias.empty())
- {
- for(int i = 0; i < certificateAlternativeNameTypesSize; ++i)
- {
- if(alias == certificateAlternativeNameTypes[i])
- {
- return i;
- }
- }
- }
- return -1; // Not supported
-}
-
-DistinguishedName
-getX509Name(SecCertificateRef cert, CFTypeRef key)
-{
- assert(key == kSecOIDX509V1IssuerName || key == kSecOIDX509V1SubjectName);
- list<pair<string, string> > rdnPairs;
- UniqueRef<CFDictionaryRef> property(getCertificateProperty(cert, key));
- if(property)
- {
- CFArrayRef dn = static_cast<CFArrayRef>(CFDictionaryGetValue(property.get(), kSecPropertyKeyValue));
- int size = CFArrayGetCount(dn);
- for(int i = 0; i < size; ++i)
- {
- CFDictionaryRef dict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(dn, i));
- rdnPairs.push_front(make_pair(
- certificateOIDAlias(
- fromCFString((static_cast<CFStringRef>(CFDictionaryGetValue(dict, kSecPropertyKeyLabel))))),
- escapeX509Name(
- fromCFString(static_cast<CFStringRef>(CFDictionaryGetValue(dict, kSecPropertyKeyValue))))));
- }
- }
- return DistinguishedName(rdnPairs);
-}
-
-vector<pair<int, string> >
-getX509AltName(SecCertificateRef cert, CFTypeRef key)
-{
- assert(key == kSecOIDIssuerAltName || key == kSecOIDSubjectAltName);
- UniqueRef<CFDictionaryRef> property(getCertificateProperty(cert, key));
-
- vector<pair<int, string> > pairs;
- if(property)
- {
- CFArrayRef names = static_cast<CFArrayRef>(CFDictionaryGetValue(property.get(), kSecPropertyKeyValue));
- int size = CFArrayGetCount(names);
-
- for(int i = 0; i < size; ++i)
- {
- CFDictionaryRef dict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(names, i));
-
- int type = certificateAlternativeNameType(
- fromCFString(static_cast<CFStringRef>(CFDictionaryGetValue(dict, kSecPropertyKeyLabel))));
- if(type != -1)
- {
- CFStringRef v = static_cast<CFStringRef>(CFDictionaryGetValue(dict, kSecPropertyKeyValue));
- CFStringRef t = static_cast<CFStringRef>(CFDictionaryGetValue(dict, kSecPropertyKeyType));
- if(CFEqual(t, kSecPropertyTypeString) || CFEqual(t, kSecPropertyTypeTitle))
- {
- pairs.push_back(make_pair(type, fromCFString(v)));
- }
- else if(CFEqual(t, kSecPropertyTypeURL))
- {
- pairs.push_back(make_pair(type, fromCFString(CFURLGetString((CFURLRef)v))));
- }
- else if(CFEqual(t, kSecPropertyTypeSection))
- {
- CFArrayRef section = (CFArrayRef)v;
- ostringstream os;
- for(int i = 0, count = CFArrayGetCount(section); i < count;)
- {
- CFDictionaryRef d = (CFDictionaryRef)CFArrayGetValueAtIndex(section, i);
-
- CFStringRef sectionLabel = static_cast<CFStringRef>(CFDictionaryGetValue(d, kSecPropertyKeyLabel));
- CFStringRef sectionValue = static_cast<CFStringRef>(CFDictionaryGetValue(d, kSecPropertyKeyValue));
-
- os << certificateOIDAlias(fromCFString(sectionLabel)) << "=" << fromCFString(sectionValue);
- if(++i < count)
- {
- os << ",";
- }
- }
- pairs.push_back(make_pair(type, os.str()));
- }
- }
- }
- }
- return pairs;
-}
-
-#ifdef ICE_CPP11_MAPPING
-chrono::system_clock::time_point
-#else
-IceUtil::Time
-#endif
-getX509Date(SecCertificateRef cert, CFTypeRef key)
-{
- assert(key == kSecOIDX509V1ValidityNotAfter || key == kSecOIDX509V1ValidityNotBefore);
- UniqueRef<CFDictionaryRef> property(getCertificateProperty(cert, key));
- CFAbsoluteTime seconds = 0;
- if(property)
- {
- CFNumberRef date = static_cast<CFNumberRef>(CFDictionaryGetValue(property.get(), kSecPropertyKeyValue));
- CFNumberGetValue(date, kCFNumberDoubleType, &seconds);
- }
-
- IceUtil::Time time = IceUtil::Time::secondsDouble(kCFAbsoluteTimeIntervalSince1970 + seconds);
-
-#ifdef ICE_CPP11_MAPPING
- return chrono::system_clock::time_point(chrono::microseconds(time.toMicroSeconds()));
-#else
- return time;
-#endif
-}
-
-string
-getX509String(SecCertificateRef cert, CFTypeRef key)
-{
- assert(key == kSecOIDX509V1SerialNumber || key == kSecOIDX509V1Version);
- UniqueRef<CFDictionaryRef> property(getCertificateProperty(cert, key));
- return property ?
- fromCFString(static_cast<CFStringRef>(CFDictionaryGetValue(property.get(), kSecPropertyKeyValue))) : "";
-}
-
-#else // IOS
-
-//
-// ASN1Parser to pase the subject/issuer ASN.1 DER encoded attributes on iOS.
-//
-class ASN1Parser
-{
-public:
-
- ASN1Parser(CFDataRef data) : _data(CFDataGetBytePtr(data)), _length(CFDataGetLength(data)), _p(_data), _next(0)
- {
- }
-
- list<pair<string, string> >
- parse()
- {
- list<pair<string, string> > rdns;
- while(_p < _data + _length)
- {
- switch(parseByte())
- {
- case 0x06: // OID
- {
- _rdn.first = parseOID();
- break;
- }
- case 0x12: // NumericString
- case 0x13: // PrintableString
- case 0x0C: // UTF8String
- case 0x16: // IA5String
- {
- _rdn.second = escapeX509Name(parseUTF8String());
- break;
- }
- case 0x30: // SEQUENCE
- case 0x31: // SET
- {
- int length = parseLength(0);
- _next = _p + length;
- if(_next > _data + _length)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, "invalid length");
- }
- break;
- }
- default:
- {
- // Unsupported tag, skip the SET.
- if(!_next)
- {
- return rdns;
- }
- _p = _next;
- _next = 0;
- break;
- }
- }
- if(_p == _next)
- {
- rdns.push_back(_rdn);
- }
- }
- return rdns;
- }
-
- string
- parseOID()
- {
- int length = parseLength(1);
- ostringstream oid;
- unsigned char c = parseByte();
- oid << c / 40 << "." << c % 40;
- while(--length > 0)
- {
- if((*_p & 0x80) == 0)
- {
- oid << "." << static_cast<int>(parseByte());
- }
- else
- {
- uint64_t result = (uint64_t)(*_p & 127);
- while(parseByte() & 128)
- {
- result = (result << 7) | (uint64_t)(*_p & 127);
- --length;
- }
- oid << "." << result;
- }
- }
- return certificateOIDAlias(oid.str());
- }
-
- string
- parseUTF8String()
- {
- int length = parseLength(0);
- string v(reinterpret_cast<const char*>(_p), length);
- _p += length;
- return v;
- }
-
- int
- parseLength(int required)
- {
- int length = 0;
- if((*_p & 0x80) == 0)
- {
- length = static_cast<int>(parseByte());
- }
- else
- {
- int nbytes = static_cast<int>(parseByte());
- for(int i = 0; i < nbytes; ++i)
- {
- length = length * 256 + parseByte();
- }
- }
- if((required > 0 && length < required) || (_p + length > _data + _length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, "invalid length");
- }
- return length;
- }
-
- unsigned char
- parseByte()
- {
- if(_p >= _data + _length)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, "invalid length");
- }
- unsigned char b = *_p++;
- return b;
- }
-
-private:
-
- const unsigned char* _data;
- const size_t _length;
- const unsigned char* _p;
- const unsigned char* _next;
- pair<string, string> _rdn;
- list<pair<string, string> > _rdns;
-};
-#endif
-
-#elif defined(ICE_USE_SCHANNEL) || defined(ICE_OS_UWP)
-
-const Ice::Long TICKS_PER_MSECOND = 10000LL;
-const Ice::Long MSECS_TO_EPOCH = 11644473600000LL;
-
-#if defined(ICE_USE_SCHANNEL)
-void
-loadCertificate(PCERT_SIGNED_CONTENT_INFO* cert, const char* buffer, DWORD length)
-{
- DWORD outLength = length;
- vector<BYTE> outBuffer;
- outBuffer.resize(outLength);
-
- if(!CryptStringToBinary(buffer, length, CRYPT_STRING_BASE64HEADER, &outBuffer[0], &outLength, 0, 0))
- {
- //
- // Base64 data should always be bigger than binary
- //
- assert(GetLastError() != ERROR_MORE_DATA);
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- DWORD decodedLeng = 0;
- if(!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, &outBuffer[0], outLength, CRYPT_DECODE_ALLOC_FLAG, 0,
- cert, &decodedLeng))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-}
-
-void
-loadCertificate(PCERT_SIGNED_CONTENT_INFO* cert, const string& file)
-{
- vector<char> buffer;
- readFile(file, buffer);
- if(buffer.empty())
- {
- throw CertificateReadException(__FILE__, __LINE__, "certificate file " + file + " is empty");
- }
- loadCertificate(cert, &buffer[0], static_cast<DWORD>(buffer.size()));
-}
-
-#ifdef ICE_CPP11_MAPPING
-chrono::system_clock::time_point
-#else
-IceUtil::Time
-#endif
-filetimeToTime(FILETIME ftime)
-{
- Ice::Long value = 0;
- DWORD* dest = reinterpret_cast<DWORD*>(&value);
- *dest++ = ftime.dwLowDateTime;
- *dest = ftime.dwHighDateTime;
-
- IceUtil::Time time = IceUtil::Time::milliSeconds((value / TICKS_PER_MSECOND) - MSECS_TO_EPOCH);
-
-#ifdef ICE_CPP11_MAPPING
- return chrono::system_clock::time_point(chrono::microseconds(time.toMicroSeconds()));
-#else
- return time;
-#endif
-
-}
-
-string
-certNameToString(CERT_NAME_BLOB* name)
-{
- assert(name);
- DWORD length = 0;
- if(!(length = CertNameToStr(X509_ASN_ENCODING, name, CERT_OID_NAME_STR|CERT_NAME_STR_REVERSE_FLAG, 0, 0)))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- vector<char> buffer(length);
- if(!CertNameToStr(X509_ASN_ENCODING, name, CERT_OID_NAME_STR|CERT_NAME_STR_REVERSE_FLAG, &buffer[0], length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- string s(&buffer[0]);
- for(int i = 0; i < certificateOIDSSize; ++i)
- {
- const CertificateOID* certificateOID = &certificateOIDS[i];
- assert(certificateOID);
- const string name = string(certificateOID->name) + "=";
- const string alias = string(certificateOID->alias) + "=";
- size_t pos = 0;
- while((pos = s.find(name, pos)) != string::npos)
- {
- s.replace(pos, name.size(), alias);
- }
- }
- return s;
-}
-
-vector<pair<int, string> >
-certificateAltNames(CERT_INFO* certInfo, LPCSTR altNameOID)
-{
- vector<pair<int, string> > altNames;
-
- PCERT_EXTENSION extension = CertFindExtension(altNameOID, certInfo->cExtension, certInfo->rgExtension);
- if(extension)
- {
- CERT_ALT_NAME_INFO* altName;
- DWORD length = 0;
- if(!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, extension->Value.pbData,
- extension->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, 0, &altName, &length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- for(DWORD i = 0; i < altName->cAltEntry; ++i)
- {
- CERT_ALT_NAME_ENTRY* entry = &altName->rgAltEntry[i];
-
- switch(entry->dwAltNameChoice)
- {
- case CERT_ALT_NAME_RFC822_NAME:
- {
- altNames.push_back(make_pair(AltNameEmail, wstringToString(entry->pwszRfc822Name)));
- break;
- }
- case CERT_ALT_NAME_DNS_NAME:
- {
- altNames.push_back(make_pair(AltNameDNS, wstringToString(entry->pwszDNSName)));
- break;
- }
- case CERT_ALT_NAME_DIRECTORY_NAME:
- {
- altNames.push_back(make_pair(AltNameDirectory, certNameToString(&entry->DirectoryName)));
- break;
- }
- case CERT_ALT_NAME_URL:
- {
- altNames.push_back(make_pair(AltNameURL, wstringToString(entry->pwszURL)));
- break;
- }
- case CERT_ALT_NAME_IP_ADDRESS:
- {
- if(entry->IPAddress.cbData == 4)
- {
- //
- // IPv4 address
- //
- ostringstream os;
- Byte* src = reinterpret_cast<Byte*>(entry->IPAddress.pbData);
- for(int j = 0; j < 4;)
- {
- int value = 0;
- Byte* dest = reinterpret_cast<Byte*>(&value);
- *dest = *src++;
- os << value;
- if(++j < 4)
- {
- os << ".";
- }
- }
- altNames.push_back(make_pair(AltNAmeIP, os.str()));
- }
- //
- // TODO IPv6 Address support.
- //
- break;
- }
- default:
- {
- // Not supported
- break;
- }
- }
- }
- LocalFree(altName);
- }
- return altNames;
-}
-#else
-
-vector<pair<int, string> >
-certificateAltNames(Windows::Security::Cryptography::Certificates::SubjectAlternativeNameInfo^ subAltNames)
-{
- vector<pair<int, string> > altNames;
- if(subAltNames)
- {
- for(auto iter = subAltNames->EmailName->First(); iter->HasCurrent; iter->MoveNext())
- {
- altNames.push_back(make_pair(AltNameEmail, wstringToString(iter->Current->Data())));
- }
- for(auto iter = subAltNames->DnsName->First(); iter->HasCurrent; iter->MoveNext())
- {
- altNames.push_back(make_pair(AltNameDNS, wstringToString(iter->Current->Data())));
- }
- for(auto iter = subAltNames->Url->First(); iter->HasCurrent; iter->MoveNext())
- {
- altNames.push_back(make_pair(AltNameURL, wstringToString(iter->Current->Data())));
- }
- for(auto iter = subAltNames->IPAddress->First(); iter->HasCurrent; iter->MoveNext())
- {
- altNames.push_back(make_pair(AltNAmeIP, wstringToString(iter->Current->Data())));
- }
- }
- return altNames;
-}
-#endif
-
-#endif
-
-CertificateReadException::CertificateReadException(const char* file, int line, const string& r) :
- ExceptionHelper<CertificateReadException>(file, line),
- reason(r)
-{
-}
-
-#ifndef ICE_CPP11_COMPILER
-CertificateReadException::~CertificateReadException() throw()
-{
-}
-#endif
-
-string
-CertificateReadException::ice_id() const
-{
- return "::IceSSL::CertificateReadException";
-}
-
-#ifndef ICE_CPP11_MAPPING
-CertificateReadException*
-CertificateReadException::ice_clone() const
-{
- return new CertificateReadException(*this);
-}
-#endif
-
-#ifdef ICE_USE_SECURE_TRANSPORT
-CertificateEncodingException::CertificateEncodingException(const char* file, int line, CFErrorRef err) :
- ExceptionHelper<CertificateEncodingException>(file, line)
-{
- assert(err);
- reason = "certificate error:\n" + errorToString(err);
-}
-#endif
-
-CertificateEncodingException::CertificateEncodingException(const char* file, int line, const string& r) :
- ExceptionHelper<CertificateEncodingException>(file, line),
- reason(r)
-{
-}
-
-#ifndef ICE_CPP11_COMPILER
-CertificateEncodingException::~CertificateEncodingException() throw()
-{
-}
-#endif
-
-string
-CertificateEncodingException::ice_id() const
-{
- return "::IceSSL::CertificateEncodingException";
-}
-
-#ifndef ICE_CPP11_MAPPING
-CertificateEncodingException*
-CertificateEncodingException::ice_clone() const
-{
- return new CertificateEncodingException(*this);
-}
-#endif
-
-#ifdef ICE_USE_OPENSSL
-
-namespace
-{
-
-IceUtil::Mutex* mut = 0;
-
-class Init
-{
-public:
-
- Init()
- {
- mut = new IceUtil::Mutex;
- }
-
- ~Init()
- {
- delete mut;
- mut = 0;
- }
-};
-
-Init init;
-
-}
-
-#ifdef ICE_CPP11_MAPPING
-chrono::system_clock::time_point
-#else
-static IceUtil::Time
-#endif
-ASMUtcTimeToTime(const ASN1_UTCTIME* s)
-{
- struct tm tm;
- int offset;
-
- memset(&tm, '\0', sizeof tm);
-
-# define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
- tm.tm_year = g2(s->data);
- if(tm.tm_year < 50)
- tm.tm_year += 100;
- tm.tm_mon = g2(s->data + 2) - 1;
- tm.tm_mday = g2(s->data + 4);
- tm.tm_hour = g2(s->data + 6);
- tm.tm_min = g2(s->data + 8);
- tm.tm_sec = g2(s->data + 10);
- if(s->data[12] == 'Z')
- {
- offset = 0;
- }
- else
- {
- offset = g2(s->data + 13) * 60 + g2(s->data + 15);
- if(s->data[12] == '-')
- {
- offset = -offset;
- }
- }
-# undef g2
-
- //
- // If timegm was on all systems this code could be
- // return IceUtil::Time::seconds(timegm(&tm) - offset*60);
- //
- // Windows doesn't support the re-entrant _r versions.
- //
- time_t tzone;
- {
- IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mut);
- time_t now = time(0);
- tzone = mktime(localtime(&now)) - mktime(gmtime(&now));
- }
-
- IceUtil::Time time = IceUtil::Time::seconds(mktime(&tm) - offset * 60 + tzone);
-
-#ifdef ICE_CPP11_MAPPING
- return chrono::system_clock::time_point(chrono::microseconds(time.toMicroSeconds()));
-#else
- return time;
-#endif
-}
-
-static string
-convertX509NameToString(X509_NAME* name)
-{
- BIO* out = BIO_new(BIO_s_mem());
- X509_NAME_print_ex(out, name, 0, XN_FLAG_RFC2253);
- BUF_MEM* p;
- BIO_get_mem_ptr(out, &p);
- string result = string(p->data, p->length);
- BIO_free(out);
- return result;
-}
-
-static vector<pair<int, string> >
-convertGeneralNames(GENERAL_NAMES* gens)
-{
- vector<pair<int, string> > alt;
- if(gens == 0)
- {
- return alt;
- }
- for(int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)
- {
- GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
- pair<int, string> p;
- p.first = gen->type;
- switch(gen->type)
- {
- case GEN_EMAIL:
- {
- ASN1_IA5STRING* str = gen->d.rfc822Name;
- if(str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
- {
- p.second = string(reinterpret_cast<const char*>(str->data), str->length);
- }
- break;
- }
- case GEN_DNS:
- {
- ASN1_IA5STRING* str = gen->d.dNSName;
- if(str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
- {
- p.second = string(reinterpret_cast<const char*>(str->data), str->length);
- }
- break;
- }
- case GEN_DIRNAME:
- {
- p.second = convertX509NameToString(gen->d.directoryName);
- break;
- }
- case GEN_URI:
- {
- ASN1_IA5STRING* str = gen->d.uniformResourceIdentifier;
- if(str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
- {
- p.second = string(reinterpret_cast<const char*>(str->data), str->length);
- }
- break;
- }
- case GEN_IPADD:
- {
- ASN1_OCTET_STRING* addr = gen->d.iPAddress;
- // TODO: Support IPv6 someday.
- if(addr && addr->type == V_ASN1_OCTET_STRING && addr->data && addr->length == 4)
- {
- ostringstream ostr;
- for(int j = 0; j < 4; ++j)
- {
- if(j > 0)
- {
- ostr << '.';
- }
- ostr << static_cast<int>(addr->data[j]);
- }
- p.second = ostr.str();
- }
- break;
- }
- case GEN_OTHERNAME:
- case GEN_EDIPARTY:
- case GEN_X400:
- case GEN_RID:
- {
- //
- // TODO: These types are not supported. If the user wants
- // them, they have to get at the certificate data. Another
- // alternative is to DER encode the data (as the Java
- // certificate does).
- //
- break;
- }
- }
- alt.push_back(p);
- }
- sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
- return alt;
-}
-#endif
-
-ParseException::ParseException(const char* file, int line, const string& r) :
- ExceptionHelper<ParseException>(file, line),
- reason(r)
-{
-}
-
-#ifndef ICE_CPP11_COMPILER
-ParseException::~ParseException() throw()
-{
-}
-#endif
-
-string
-ParseException::ice_id() const
-{
- return "::IceSSL::ParseException";
-}
-
-#ifndef ICE_CPP11_MAPPING
-ParseException*
-ParseException::ice_clone() const
-{
- return new ParseException(*this);
-}
-#endif
-
-#ifdef ICE_USE_OPENSSL
-DistinguishedName::DistinguishedName(X509NAME* name) : _rdns(RFC2253::parseStrict(convertX509NameToString(name)))
-{
- unescape();
-}
-#endif
-
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
-DistinguishedName::DistinguishedName(CFDataRef data) : _rdns(ASN1Parser(data).parse())
-{
- unescape();
-}
-#endif
-
-DistinguishedName::DistinguishedName(const string& dn) : _rdns(RFC2253::parseStrict(dn))
-{
- unescape();
-}
-
-DistinguishedName::DistinguishedName(const list<pair<string, string> >& rdns) : _rdns(rdns)
-{
- unescape();
-}
-
-namespace IceSSL
-{
-
-bool
-operator==(const DistinguishedName& lhs, const DistinguishedName& rhs)
-{
- return lhs._unescaped == rhs._unescaped;
-}
-
-bool
-operator<(const DistinguishedName& lhs, const DistinguishedName& rhs)
-{
- return lhs._unescaped == rhs._unescaped;
-}
-
-}
-
-bool
-DistinguishedName::match(const DistinguishedName& other) const
-{
- for(list< pair<string, string> >::const_iterator p = other._unescaped.begin(); p != other._unescaped.end(); ++p)
- {
- bool found = false;
- for(list< pair<string, string> >::const_iterator q = _unescaped.begin(); q != _unescaped.end(); ++q)
- {
- if(p->first == q->first)
- {
- found = true;
- if(p->second != q->second)
- {
- return false;
- }
- }
- }
- if(!found)
- {
- return false;
- }
- }
- return true;
-}
-
-bool
-DistinguishedName::match(const string& other) const
-{
- return match(DistinguishedName(other));
-}
-
-//
-// This always produces the same output as the input DN -- the type of
-// escaping is not changed.
-//
-DistinguishedName::operator string() const
-{
- ostringstream os;
- bool first = true;
- for(list< pair<string, string> >::const_iterator p = _rdns.begin(); p != _rdns.end(); ++p)
- {
- if(!first)
- {
- os << ",";
- }
- first = false;
- os << p->first << "=" << p->second;
- }
- return os.str();
-}
-
-void
-DistinguishedName::unescape()
-{
- for(list< pair<string, string> >::const_iterator q = _rdns.begin(); q != _rdns.end(); ++q)
- {
- pair<string, string> rdn = *q;
- rdn.second = RFC2253::unescape(rdn.second);
- _unescaped.push_back(rdn);
- }
-}
-
-PublicKey::PublicKey(const CertificatePtr& cert, KeyRef key) :
- _cert(cert),
- _key(key)
-{
- if(!_key)
- {
- throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Invalid key reference");
- }
-}
-
-//
-// With SecureTransport the key is UniqueRef and will be automatically released.
-// With SChannel the key is owned by the certificate and there is no need
-// for release it.
-//
-#ifdef ICE_USE_OPENSSL
-PublicKey::~PublicKey()
-{
- if(_key)
- {
- EVP_PKEY_free(_key);
- }
-}
-#endif
-
-KeyRef
-PublicKey::key() const
-{
-#ifdef __APPLE__
- return _key.get();
-#else
- return _key;
-#endif
-}
-
-#if defined(ICE_USE_OPENSSL) || defined(ICE_USE_SCHANNEL)
-
-X509Extension::X509Extension(X509ExtensionRef extension, const string& oid, const CertificatePtr& cert) :
- _extension(extension),
- _oid(oid),
- _cert(cert)
-{
-}
-
-X509Extension::~X509Extension()
-{
-}
-
-bool
-X509Extension::isCritical() const
-{
-#if defined(ICE_USE_OPENSSL)
- return X509_EXTENSION_get_critical(_extension) == 1;
-#elif defined(ICE_USE_SCHANNEL)
- return _extension.fCritical;
-#endif
-}
-
-string
-X509Extension::getOID() const
-{
- return _oid;
-}
-
-vector<Ice::Byte>
-X509Extension::getData() const
-{
- vector<Ice::Byte> data;
-#if defined(ICE_USE_OPENSSL)
- ASN1_OCTET_STRING* buffer = X509_EXTENSION_get_data(_extension);
- assert(buffer);
- data.resize(buffer->length);
- memcpy(&data[0], buffer->data, buffer->length);
-#elif defined(ICE_USE_SCHANNEL)
- data.resize(_extension.Value.cbData);
- memcpy(&data[0], _extension.Value.pbData, _extension.Value.cbData);
-#endif
- return data;
-}
-
-#endif
-
-//
-// The caller is responsible for incrementing the reference count.
-//
-Certificate::Certificate(X509CertificateRef cert) : _cert(cert)
-{
- if(!_cert)
- {
- throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Invalid certificate reference");
- }
-
-#if defined(ICE_USE_SCHANNEL)
- _certInfo = 0;
- try
- {
- //
- // Decode certificate info
- //
- DWORD length = 0;
- if(!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, _cert->ToBeSigned.pbData,
- _cert->ToBeSigned.cbData, CRYPT_DECODE_ALLOC_FLAG, 0, &_certInfo, &length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
- }
- catch(...)
- {
- LocalFree(_cert);
- _cert = 0;
- throw;
- }
-#endif
-}
-
-#if defined(ICE_USE_OPENSSL) || defined(ICE_USE_SCHANNEL)
-
-void
-Certificate::loadX509Extensions() const
-{
- IceUtil::Mutex::Lock sync(*this);
- if(_extensions.empty())
- {
-#if defined(ICE_USE_SCHANNEL)
- for(size_t i = 0; i < _certInfo->cExtension; ++i)
- {
- CERT_EXTENSION ext = _certInfo->rgExtension[i];
- _extensions.push_back(ICE_MAKE_SHARED(X509Extension, ext, ext.pszObjId, ICE_SHARED_FROM_CONST_THIS(Certificate)));
- }
-#elif defined(ICE_USE_OPENSSL)
- int sz = X509_get_ext_count(_cert);
- for(int i = 0; i < sz; i++)
- {
- X509_EXTENSION* ext = X509_get_ext(_cert, i);
- ASN1_OBJECT* obj = X509_EXTENSION_get_object(ext);
- string oid;
- //
- // According to OBJ_obj2txt doc a buffer of length 80 should be more than enough to
- // handle any OID encountered in practice.
- //
- int len = 80;
- oid.resize(len);
- len = OBJ_obj2txt(&oid[0], len, obj, 1);
- oid.resize(len);
- _extensions.push_back(ICE_MAKE_SHARED(X509Extension, ext, oid, ICE_SHARED_FROM_CONST_THIS(Certificate)));
- }
-#endif
- }
-}
-
-vector<X509ExtensionPtr>
-Certificate::getX509Extensions() const
-{
- loadX509Extensions(); // Lazzy initialize the extensions
- return _extensions;
-}
-
-X509ExtensionPtr
-Certificate::getX509Extension(const string& oid) const
-{
- loadX509Extensions(); // Lazzy initialize the extensions
- X509ExtensionPtr ext;
- for(vector<X509ExtensionPtr>::const_iterator i = _extensions.begin(); i != _extensions.end(); ++i)
- {
- if((*i)->getOID() == oid)
- {
- ext = *i;
- break;
- }
- }
- return ext;
-}
-#endif
-
-Certificate::~Certificate()
-{
- if(_cert)
- {
-#if defined(ICE_USE_SCHANNEL)
- LocalFree(_cert);
- if(_certInfo)
- {
- LocalFree(_certInfo);
- }
-#elif defined(ICE_USE_OPENSSL)
- X509_free(_cert);
-#endif
- }
-}
-
-CertificatePtr
-Certificate::load(const string& file)
-{
-#if defined(ICE_USE_SECURE_TRANSPORT)
- string resolved;
- if(checkPath(file, "", false, resolved))
- {
- return ICE_MAKE_SHARED(Certificate, loadCertificate(resolved));
- }
- else
- {
- throw CertificateReadException(__FILE__, __LINE__, "error opening file " + file);
- }
-#elif defined(ICE_USE_SCHANNEL)
- CERT_SIGNED_CONTENT_INFO* cert;
- loadCertificate(&cert, file);
- return ICE_MAKE_SHARED(Certificate, cert);
-#elif defined(ICE_USE_OPENSSL)
- BIO *cert = BIO_new(BIO_s_file());
- if(BIO_read_filename(cert, file.c_str()) <= 0)
- {
- BIO_free(cert);
- throw CertificateReadException(__FILE__, __LINE__, "error opening file");
- }
-
- X509CertificateRef x = PEM_read_bio_X509_AUX(cert, ICE_NULLPTR, ICE_NULLPTR, ICE_NULLPTR);
- if(x == ICE_NULLPTR)
- {
- BIO_free(cert);
- throw CertificateReadException(__FILE__, __LINE__, "error reading file:\n" + getSslErrors(false));
- }
- BIO_free(cert);
- return ICE_MAKE_SHARED(Certificate, x);
-#elif defined(ICE_OS_UWP)
- try
- {
- auto uri = ref new Uri(ref new String(stringToWstring(file).c_str()));
- auto file = create_task(StorageFile::GetFileFromApplicationUriAsync(uri)).get();
- auto buffer = create_task(FileIO::ReadTextAsync(file)).get();
- return Certificate::decode(wstringToString(buffer->Data()));
- }
- catch(Platform::Exception^ ex)
- {
- if(HRESULT_CODE(ex->HResult) == ERROR_FILE_NOT_FOUND)
- {
- throw CertificateReadException(__FILE__, __LINE__, "error opening file :" + file);
- }
- else
- {
- throw Ice::SyscallException(__FILE__, __LINE__, ex->HResult);
- }
- }
-#else
-# error "Unknown platform"
-#endif
-}
-
-CertificatePtr
-Certificate::decode(const string& encoding)
-{
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- string::size_type size, startpos, endpos = 0;
- startpos = encoding.find("-----BEGIN CERTIFICATE-----", endpos);
- if(startpos != string::npos)
- {
- startpos += sizeof("-----BEGIN CERTIFICATE-----");
- endpos = encoding.find("-----END CERTIFICATE-----", startpos);
- size = endpos - startpos;
- }
- else
- {
- startpos = 0;
- endpos = string::npos;
- size = encoding.size();
- }
-
- vector<unsigned char> data(IceInternal::Base64::decode(string(&encoding[startpos], size)));
- UniqueRef<CFDataRef> certdata(CFDataCreate(kCFAllocatorDefault, &data[0], data.size()));
- SecCertificateRef cert = SecCertificateCreateWithData(0, certdata.get());
- if(!cert)
- {
- assert(false);
- throw CertificateEncodingException(__FILE__, __LINE__, "certificate is not a valid PEM-encoded certificate");
- }
- return ICE_MAKE_SHARED(Certificate, cert);
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- UniqueRef<CFDataRef> data(
- CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
- reinterpret_cast<const UInt8*>(encoding.c_str()),
- encoding.size(), kCFAllocatorNull));
-
- SecExternalFormat format = kSecFormatUnknown;
- SecExternalItemType type = kSecItemTypeCertificate;
-
- SecItemImportExportKeyParameters params;
- memset(&params, 0, sizeof(params));
- params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
-
- UniqueRef<CFArrayRef> items;
- OSStatus err = SecItemImport(data.get(), 0, &format, &type, 0, &params, 0, &items.get());
- if(err)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, errorToString(err));
- }
-
- UniqueRef<SecKeychainItemRef> item;
- item.retain(static_cast<SecKeychainItemRef>(const_cast<void*>(CFArrayGetValueAtIndex(items.get(), 0))));
- assert(SecCertificateGetTypeID() == CFGetTypeID(item.get()));
- return ICE_MAKE_SHARED(Certificate, reinterpret_cast<SecCertificateRef>(item.release()));
-#elif defined(ICE_USE_SCHANNEL)
- CERT_SIGNED_CONTENT_INFO* cert;
- loadCertificate(&cert, encoding.c_str(), static_cast<DWORD>(encoding.size()));
- return ICE_MAKE_SHARED(Certificate, cert);
-#elif defined(ICE_USE_OPENSSL)
- BIO *cert = BIO_new_mem_buf(static_cast<void*>(const_cast<char*>(&encoding[0])), static_cast<int>(encoding.size()));
- X509CertificateRef x = PEM_read_bio_X509_AUX(cert, ICE_NULLPTR, ICE_NULLPTR, ICE_NULLPTR);
- if(x == ICE_NULLPTR)
- {
- BIO_free(cert);
- throw CertificateEncodingException(__FILE__, __LINE__, getSslErrors(false));
- }
- BIO_free(cert);
- return ICE_MAKE_SHARED(Certificate, x);
-#elif defined(ICE_OS_UWP)
- string::size_type size, startpos, endpos = 0;
- startpos = encoding.find("-----BEGIN CERTIFICATE-----", endpos);
- if (startpos != string::npos)
- {
- startpos += sizeof("-----BEGIN CERTIFICATE-----");
- endpos = encoding.find("-----END CERTIFICATE-----", startpos);
- size = endpos - startpos;
- }
- else
- {
- startpos = 0;
- endpos = string::npos;
- size = encoding.size();
- }
-
- vector<unsigned char> data(IceInternal::Base64::decode(string(&encoding[startpos], size)));
- auto writer = ref new DataWriter();
- writer->WriteBytes(Platform::ArrayReference<unsigned char>(&data[0], static_cast<unsigned int>(data.size())));
- return make_shared<Certificate>(ref new Certificates::Certificate(writer->DetachBuffer()));
-#else
-# error "Unknown platform"
-#endif
-}
-
-bool
-Certificate::operator==(const Certificate& other) const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT)
- return CFEqual(_cert.get(), other._cert.get());
-#elif defined(ICE_USE_SCHANNEL)
- return CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, _certInfo, other._certInfo);
-#elif defined(ICE_USE_OPENSSL)
- return X509_cmp(_cert, other._cert) == 0;
-#elif defined(ICE_OS_UWP)
- return CryptographicBuffer::Compare(_cert->GetCertificateBlob(), other._cert->GetCertificateBlob());
-#else
-# error "Unknown platform"
-#endif
-}
-
-bool
-Certificate::operator!=(const Certificate& other) const
-{
- return !operator==(other);
-}
-
-vector<Ice::Byte>
-Certificate::getAuthorityKeyIdentifier() const
-{
- vector<Ice::Byte> keyid;
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- // Not supported
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- UniqueRef<CFDictionaryRef> property(getCertificateProperty(_cert.get(), kSecOIDAuthorityKeyIdentifier));
- if(property)
- {
- CFTypeRef type = 0;
- CFTypeRef value;
- if(CFDictionaryGetValueIfPresent(property.get(), kSecPropertyKeyType, &type))
- {
- if(CFEqual(type, kSecPropertyTypeSection))
- {
- if(CFDictionaryGetValueIfPresent(property.get(), kSecPropertyKeyValue, &value))
- {
- if(CFArrayGetCount(static_cast<CFArrayRef>(value)) >= 0)
- {
- value = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(value), 1);
- type = CFDictionaryGetValue(static_cast<CFDictionaryRef>(value), kSecPropertyKeyType);
- }
- }
- }
-
- if(CFEqual(type, kSecPropertyTypeData))
- {
- CFDataRef data = static_cast<CFDataRef>(
- CFDictionaryGetValue(static_cast<CFDictionaryRef>(value), kSecPropertyKeyValue));
- keyid.resize(CFDataGetLength(data));
- memcpy(&keyid[0], CFDataGetBytePtr(data), CFDataGetLength(data));
- }
- }
- }
-#elif defined(ICE_USE_SCHANNEL)
- PCERT_EXTENSION extension = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, _certInfo->cExtension,
- _certInfo->rgExtension);
- if(extension)
- {
- CERT_AUTHORITY_KEY_ID2_INFO* decoded;
- DWORD length = 0;
- if(!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID2, extension->Value.pbData,
- extension->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, 0, &decoded, &length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- if(decoded->KeyId.pbData && decoded->KeyId.cbData)
- {
- keyid.resize(decoded->KeyId.cbData);
- memcpy(&keyid[0], decoded->KeyId.pbData, decoded->KeyId.cbData);
- LocalFree(decoded);
- }
- }
-#elif defined(ICE_USE_OPENSSL)
- int index = X509_get_ext_by_NID(_cert, NID_authority_key_identifier, -1);
- if(index >= 0)
- {
- X509_EXTENSION* ext = X509_get_ext(_cert, index);
- if(ext)
- {
- AUTHORITY_KEYID* decoded = (AUTHORITY_KEYID*)X509V3_EXT_d2i(ext);
- if(!decoded)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, "the extension could not be decoded");
- }
- keyid.resize(decoded->keyid->length);
- memcpy(&keyid[0], decoded->keyid->data, decoded->keyid->length);
- AUTHORITY_KEYID_free(decoded);
- }
- }
-#elif defined(ICE_OS_UWP)
- // Not supported
-#else
-# error "Unknown platform"
-#endif
- return keyid;
-}
-
-vector<Ice::Byte>
-Certificate::getSubjectKeyIdentifier() const
-{
- vector<Ice::Byte> keyid;
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- // Not supported
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- UniqueRef<CFDictionaryRef> property(getCertificateProperty(_cert.get(), kSecOIDSubjectKeyIdentifier));
- if(property)
- {
- CFTypeRef type = 0;
- CFTypeRef value;
- if(CFDictionaryGetValueIfPresent(property.get(), kSecPropertyKeyType, &type))
- {
- if(CFEqual(type, kSecPropertyTypeSection))
- {
- if(CFDictionaryGetValueIfPresent(property.get(), kSecPropertyKeyValue, &value))
- {
- if(CFArrayGetCount(static_cast<CFArrayRef>(value)) >= 0)
- {
- value = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(value), 1);
- type = CFDictionaryGetValue(static_cast<CFDictionaryRef>(value), kSecPropertyKeyType);
- }
- }
- }
-
- if(CFEqual(type, kSecPropertyTypeData))
- {
- CFDataRef data = static_cast<CFDataRef>(
- CFDictionaryGetValue(static_cast<CFDictionaryRef>(value), kSecPropertyKeyValue));
- keyid.resize(CFDataGetLength(data));
- memcpy(&keyid[0], CFDataGetBytePtr(data), CFDataGetLength(data));
- }
- }
- }
-#elif defined(ICE_USE_SCHANNEL)
- PCERT_EXTENSION extension = CertFindExtension(szOID_SUBJECT_KEY_IDENTIFIER, _certInfo->cExtension,
- _certInfo->rgExtension);
- if(extension)
- {
- CRYPT_DATA_BLOB* decoded;
- DWORD length = 0;
- if(!CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_SUBJECT_KEY_IDENTIFIER, extension->Value.pbData,
- extension->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, 0, &decoded, &length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- if(decoded->pbData && decoded->cbData)
- {
- keyid.resize(decoded->cbData);
- memcpy(&keyid[0], decoded->pbData, decoded->cbData);
- LocalFree(decoded);
- }
- }
-#elif defined(ICE_USE_OPENSSL)
- int index = X509_get_ext_by_NID(_cert, NID_subject_key_identifier, -1);
- if(index >= 0)
- {
- X509_EXTENSION* ext = X509_get_ext(_cert, index);
- if(ext)
- {
- ASN1_OCTET_STRING* decoded = static_cast<ASN1_OCTET_STRING*>(X509V3_EXT_d2i(ext));
- if(!decoded)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, "the extension could not be decoded");
- }
- keyid.resize(decoded->length);
- memcpy(&keyid[0], decoded->data, decoded->length);
- ASN1_OCTET_STRING_free(decoded);
- }
- }
-#elif defined(ICE_OS_UWP)
- // Not supported
-#else
-# error "Unknown platform"
-#endif
- return keyid;
-}
-
-PublicKeyPtr
-Certificate::getPublicKey() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- return ICE_NULLPTR; // Not supported
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- UniqueRef<SecKeyRef> key;
- OSStatus err = SecCertificateCopyPublicKey(_cert.get(), &key.get());
- if(err)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, errorToString(err));
- }
- return ICE_MAKE_SHARED(PublicKey, ICE_SHARED_FROM_CONST_THIS(Certificate), key.release());
-#elif defined(ICE_USE_SCHANNEL)
- return ICE_MAKE_SHARED(PublicKey, ICE_SHARED_FROM_CONST_THIS(Certificate), &_certInfo->SubjectPublicKeyInfo);
-#elif defined(ICE_USE_OPENSSL)
- return ICE_MAKE_SHARED(PublicKey, ICE_SHARED_FROM_CONST_THIS(Certificate), X509_get_pubkey(_cert));
-#elif defined(ICE_OS_UWP)
- return ICE_NULLPTR; // Not supported
-#else
-# error "Unknown platform"
-#endif
-}
-
-bool
-Certificate::verify(const CertificatePtr& cert) const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT)
- //
- // We first check if the given certificate subject match our certificate
- // issuer. Otherwhise when checking a certificate against itself
- // SecTrustEvaluate always returns it is valid.
- //
- bool valid = false;
-
-# if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- initializeAttributes();
- cert->initializeAttributes();
- valid = CFEqual(_issuer.get(), cert->_subject.get());
-# else
- UniqueRef<CFErrorRef> error;
- UniqueRef<CFDataRef> issuer(SecCertificateCopyNormalizedIssuerContent(_cert.get(), &error.get()));
- if(error)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, error.get());
- }
- UniqueRef<CFDataRef> subject(SecCertificateCopyNormalizedSubjectContent(cert->getCert(), &error.get()));
- if(error)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, error.get());
- }
-
- //
- // The certificate issuer must match the CA subject.
- //
- valid = CFEqual(issuer.get(), subject.get());
-# endif
- if(valid)
- {
- UniqueRef<SecPolicyRef> policy(SecPolicyCreateBasicX509());
- UniqueRef<SecTrustRef> trust;
- OSStatus err = 0;;
- if((err = SecTrustCreateWithCertificates(_cert.get(), policy.get(), &trust.get())))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, errorToString(err));
- }
-
- SecCertificateRef certs[1] = { cert->getCert() };
- UniqueRef<CFArrayRef> anchorCertificates(
- CFArrayCreate(kCFAllocatorDefault, (const void**)&certs, 1, &kCFTypeArrayCallBacks));
- if((err = SecTrustSetAnchorCertificates(trust.get(), anchorCertificates.get())))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, errorToString(err));
- }
-
- SecTrustResultType trustResult = kSecTrustResultInvalid;
- if((err = SecTrustEvaluate(trust.get(), &trustResult)))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, errorToString(err));
- }
-
- valid = trustResult == kSecTrustResultUnspecified;
- }
- return valid;
-#elif defined(ICE_USE_SCHANNEL)
- BYTE* buffer = 0;
- DWORD length = 0;
- if(!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, _cert, CRYPT_ENCODE_ALLOC_FLAG , 0, &buffer, &length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- bool result = CryptVerifyCertificateSignature(0, X509_ASN_ENCODING, buffer, length, cert->getPublicKey()->key());
- LocalFree(buffer);
- return result;
-#elif defined(ICE_USE_OPENSSL)
- return X509_verify(_cert, cert->getPublicKey()->key()) > 0;
-#elif defined(ICE_OS_UWP)
- return false;
-#else
-# error "Unknown platform"
-#endif
-}
-
-#ifdef ICE_USE_OPENSSL
-bool
-Certificate::verify(const PublicKeyPtr& key) const
-{
- return X509_verify(_cert, key->key()) > 0;
-}
-#endif
-
-string
-Certificate::encode() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- UniqueRef<CFDataRef> cert(SecCertificateCopyData(_cert.get()));
- vector<unsigned char> data(CFDataGetBytePtr(cert.get()), CFDataGetBytePtr(cert.get()) + CFDataGetLength(cert.get()));
- ostringstream os;
- os << "-----BEGIN CERTIFICATE-----\n";
- os << IceInternal::Base64::encode(data);
- os << "-----END CERTIFICATE-----\n";
- return os.str();
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- UniqueRef<CFDataRef> exported;
- OSStatus err = SecItemExport(_cert.get(), kSecFormatPEMSequence, kSecItemPemArmour, 0, &exported.get());
- if(err != noErr)
- {
- throw CertificateEncodingException(__FILE__, __LINE__, errorToString(err));
- }
- return string(reinterpret_cast<const char*>(CFDataGetBytePtr(exported.get())), CFDataGetLength(exported.get()));
-#elif defined(ICE_USE_SCHANNEL)
- string s;
- DWORD length = 0;
- BYTE* buffer = 0;
- try
- {
- if(!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, _cert, CRYPT_ENCODE_ALLOC_FLAG , 0, &buffer, &length))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- DWORD encodedLength = 0;
- if(!CryptBinaryToString(buffer, length, CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, 0, &encodedLength))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
-
- std::vector<char> encoded;
- encoded.resize(encodedLength);
- if(!CryptBinaryToString(buffer, length, CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, &encoded[0],
- &encodedLength))
- {
- throw CertificateEncodingException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString());
- }
- LocalFree(buffer);
- buffer = 0;
- s.assign(&encoded[0]);
- }
- catch(...)
- {
- if(buffer)
- {
- LocalFree(buffer);
- }
- throw;
- }
- return s;
-#elif defined(ICE_USE_OPENSSL)
- BIO* out = BIO_new(BIO_s_mem());
- int i = PEM_write_bio_X509_AUX(out, _cert);
- if(i <= 0)
- {
- BIO_free(out);
- throw CertificateEncodingException(__FILE__, __LINE__, getSslErrors(false));
- }
- BUF_MEM* p;
- BIO_get_mem_ptr(out, &p);
- string result = string(p->data, p->length);
- BIO_free(out);
- return result;
-#elif defined(ICE_OS_UWP)
- auto reader = Windows::Storage::Streams::DataReader::FromBuffer(_cert->GetCertificateBlob());
- std::vector<unsigned char> data(reader->UnconsumedBufferLength);
- if(!data.empty())
- {
- reader->ReadBytes(Platform::ArrayReference<unsigned char>(&data[0], static_cast<unsigned int>(data.size())));
- }
- ostringstream os;
- os << "-----BEGIN CERTIFICATE-----\n";
- os << IceInternal::Base64::encode(data);
- os << "-----END CERTIFICATE-----\n";
- return os.str();
-#else
-# error "Unknown platform"
-#endif
-}
-
-#if !defined(ICE_USE_SECURE_TRANSPORT_IOS)
-
-bool
-Certificate::checkValidity() const
-{
-#ifdef ICE_CPP11_MAPPING
- auto now = chrono::system_clock::now();
-#else
- IceUtil::Time now = IceUtil::Time::now();
-#endif
- return now > getNotBefore() && now <= getNotAfter();
-}
-
-bool
-#ifdef ICE_CPP11_MAPPING
-Certificate::checkValidity(const chrono::system_clock::time_point& now) const
-#else
-Certificate::checkValidity(const IceUtil::Time& now) const
-#endif
-{
- return now > getNotBefore() && now <= getNotAfter();
-}
-
-#ifdef ICE_CPP11_MAPPING
-chrono::system_clock::time_point
-#else
-IceUtil::Time
-#endif
-Certificate::getNotAfter() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT)
- return getX509Date(_cert.get(), kSecOIDX509V1ValidityNotAfter);
-#elif defined(ICE_USE_SCHANNEL)
- return filetimeToTime(_certInfo->NotAfter);
-#elif defined(ICE_USE_OPENSSL)
- return ASMUtcTimeToTime(X509_get_notAfter(_cert));
-#elif defined(ICE_OS_UWP)
- // Convert 100ns time from January 1, 1601 to ms from January 1, 1970
- IceUtil::Time time = IceUtil::Time::milliSeconds(_cert->ValidTo.UniversalTime / TICKS_PER_MSECOND - MSECS_TO_EPOCH);
-# ifdef ICE_CPP11_MAPPING
- return chrono::system_clock::time_point(chrono::microseconds(time.toMicroSeconds()));
-# else
- return time;
-# endif
-
-#else
-# error "Unknown platform"
-#endif
-}
-
-#ifdef ICE_CPP11_MAPPING
-chrono::system_clock::time_point
-#else
-IceUtil::Time
-#endif
-Certificate::getNotBefore() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT)
- return getX509Date(_cert.get(), kSecOIDX509V1ValidityNotBefore);
-#elif defined(ICE_USE_SCHANNEL)
- return filetimeToTime(_certInfo->NotBefore);
-#elif defined(ICE_USE_OPENSSL)
- return ASMUtcTimeToTime(X509_get_notBefore(_cert));
-#elif defined(ICE_OS_UWP)
- // Convert 100ns time from January 1, 1601 to ms from January 1, 1970
- IceUtil::Time time = IceUtil::Time::milliSeconds(_cert->ValidFrom.UniversalTime / TICKS_PER_MSECOND - MSECS_TO_EPOCH);
-# ifdef ICE_CPP11_MAPPING
- return chrono::system_clock::time_point(chrono::microseconds(time.toMicroSeconds()));
-# else
- return time;
-# endif
-
-#else
-# error "Unknown platform"
-#endif
-}
-
-#endif
-
-string
-Certificate::getSerialNumber() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- initializeAttributes();
- return _serial;
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- return getX509String(_cert.get(), kSecOIDX509V1SerialNumber);
-#elif defined(ICE_USE_SCHANNEL)
- ostringstream os;
- for(int i = _certInfo->SerialNumber.cbData - 1; i >= 0; --i)
- {
- unsigned char c = _certInfo->SerialNumber.pbData[i];
- os.fill('0');
- os.width(2);
- os << hex << static_cast<int>(c);
- if(i)
- {
- os << ' ';
- }
- }
- return IceUtilInternal::toUpper(os.str());
-#elif defined(ICE_USE_OPENSSL)
- BIGNUM* bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(_cert), 0);
- char* dec = BN_bn2dec(bn);
- string result = dec;
- OPENSSL_free(dec);
- BN_free(bn);
-
- return result;
-#elif defined(ICE_OS_UWP)
- ostringstream os;
- os.fill(0);
- os.width(2);
- for (unsigned int i = 0; i < _cert->SerialNumber->Length; i++)
- {
- os << hex << static_cast<int>(_cert->SerialNumber[i]);
- }
- return IceUtilInternal::toUpper(os.str());
-#else
-# error "Unknown platform"
-#endif
-}
-
-DistinguishedName
-Certificate::getIssuerDN() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- initializeAttributes();
- return _issuer ? DistinguishedName(_issuer.get()) : DistinguishedName("");
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- return getX509Name(_cert.get(), kSecOIDX509V1IssuerName);
-#elif defined(ICE_USE_SCHANNEL)
- return DistinguishedName(certNameToString(&_certInfo->Issuer));
-#elif defined(ICE_USE_OPENSSL)
- return DistinguishedName(RFC2253::parseStrict(convertX509NameToString(X509_get_issuer_name(_cert))));
-#elif defined(ICE_OS_UWP)
- ostringstream os;
- os << "CN=" << wstringToString(_cert->Issuer->Data());
- return DistinguishedName(os.str());
-#else
-# error "Unknown platform"
-#endif
-}
-
-#if !defined(ICE_USE_SECURE_TRANSPORT_IOS)
-vector<pair<int, string> >
-Certificate::getIssuerAlternativeNames()
-{
-#if defined(ICE_USE_SECURE_TRANSPORT)
- return getX509AltName(_cert.get(), kSecOIDIssuerAltName);
-#elif defined(ICE_USE_SCHANNEL)
- return certificateAltNames(_certInfo, szOID_ISSUER_ALT_NAME2);
-#elif defined(ICE_USE_OPENSSL)
- return convertGeneralNames(reinterpret_cast<GENERAL_NAMES*>(X509_get_ext_d2i(_cert, NID_issuer_alt_name, 0, 0)));
-#elif defined(ICE_OS_UWP)
- return vector<pair<int, string> >(); // Not supported
-#else
-# error "Unknown platform"
-#endif
-}
-#endif
-
-DistinguishedName
-Certificate::getSubjectDN() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- initializeAttributes();
- if(_subject)
- {
- return DistinguishedName(_subject.get());
- }
- else
- {
- UniqueRef<CFStringRef> subjectSummary(SecCertificateCopySubjectSummary(_cert.get()));
- return DistinguishedName("CN=" + fromCFString(subjectSummary.get()));
- }
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- return getX509Name(_cert.get(), kSecOIDX509V1SubjectName);
-#elif defined(ICE_USE_SCHANNEL)
- return DistinguishedName(certNameToString(&_certInfo->Subject));
-#elif defined(ICE_USE_OPENSSL)
- return DistinguishedName(RFC2253::parseStrict(convertX509NameToString(X509_get_subject_name(_cert))));
-#elif defined(ICE_OS_UWP)
- ostringstream os;
- os << "CN=" << wstringToString(_cert->Subject->Data());
- return DistinguishedName(os.str());
-#else
-# error "Unknown platform"
-#endif
-}
-
-#if !defined(ICE_USE_SECURE_TRANSPORT_IOS)
-vector<pair<int, string> >
-Certificate::getSubjectAlternativeNames()
-{
-#if defined(ICE_USE_SECURE_TRANSPORT)
- return getX509AltName(_cert.get(), kSecOIDSubjectAltName);
-#elif defined(ICE_USE_SCHANNEL)
- return certificateAltNames(_certInfo, szOID_SUBJECT_ALT_NAME2);
-#elif defined(ICE_USE_OPENSSL)
- return convertGeneralNames(reinterpret_cast<GENERAL_NAMES*>(X509_get_ext_d2i(_cert, NID_subject_alt_name, 0, 0)));
-#elif defined(ICE_OS_UWP)
- return certificateAltNames(_cert->SubjectAlternativeName);
-#else
-# error "Unknown platform"
-#endif
-}
-#endif
-
-int
-Certificate::getVersion() const
-{
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
- initializeAttributes();
- return _version;
-#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS)
- return atoi(getX509String(_cert.get(), kSecOIDX509V1Version).c_str()) - 1;
-#elif defined(ICE_USE_SCHANNEL)
- return _certInfo->dwVersion;
-#elif defined(ICE_USE_OPENSSL)
- return static_cast<int>(X509_get_version(_cert));
-#elif defined(ICE_OS_UWP)
- return -1; // Not supported
-#else
-# error "Unknown platform"
-#endif
-}
-
-string
-Certificate::toString() const
-{
- ostringstream os;
- os << "serial: " << getSerialNumber() << "\n";
- os << "issuer: " << string(getIssuerDN()) << "\n";
- os << "subject: " << string(getSubjectDN()) << "\n";
-#if !defined(ICE_USE_SECURE_TRANSPORT_IOS)
-
-# ifdef ICE_CPP11_MAPPING
- // Precision is only seconds here, which is probably fine
- os << "notBefore: " << IceUtil::Time::seconds(chrono::system_clock::to_time_t(getNotBefore())).toDateTime() << "\n";
- os << "notAfter: " << IceUtil::Time::seconds(chrono::system_clock::to_time_t(getNotAfter())).toDateTime();
-# else
- os << "notBefore: " << getNotBefore().toDateTime() << "\n";
- os << "notAfter: " << getNotAfter().toDateTime();
-# endif
-
-#endif
- return os.str();
-}
-
-X509CertificateRef
-Certificate::getCert() const
-{
-#ifdef __APPLE__
- return _cert.get();
-#else
- return _cert;
-#endif
-}
-
-#if defined(ICE_USE_SECURE_TRANSPORT_IOS)
-
-namespace
-{
-
-IceUtil::Mutex* globalMutex = 0;
-
-class Init
-{
-public:
-
- Init()
- {
- globalMutex = new IceUtil::Mutex;
- }
-
- ~Init()
- {
- delete globalMutex;
- globalMutex = 0;
- }
-};
-
-Init init;
-
-}
-
-void
-Certificate::initializeAttributes() const
-{
- //
- // We need to temporarily add the certificate to the keychain in order to
- // retrieve its attributes. Unfortunately kSecMatchItemList doesn't work
- // on iOS. We make sure only one thread adds/removes a cert at a time here.
- //
- IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(globalMutex);
-
- if(_subject)
- {
- return;
- }
-
- UniqueRef<CFMutableDictionaryRef> query(
- CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
- CFDictionarySetValue(query.get(), kSecValueRef, _cert.get());
- CFDictionarySetValue(query.get(), kSecReturnAttributes, kCFBooleanTrue);
-
- UniqueRef<CFDictionaryRef> attributes(0);
- OSStatus err;
- if((err = SecItemAdd(query.get(), reinterpret_cast<CFTypeRef*>(&attributes.get()))) == errSecDuplicateItem)
- {
- CFDictionarySetValue(query.get(), kSecClass, kSecClassCertificate);
- err = SecItemCopyMatching(query.get(), reinterpret_cast<CFTypeRef*>(&attributes.get()));
- }
- else
- {
- query.reset(CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
- CFDictionarySetValue(query.get(), kSecClass, kSecClassCertificate);
- CFDictionarySetValue(query.get(), kSecValueRef, _cert.get());
- err = SecItemDelete(query.get());
- }
-
- if(err != noErr)
- {
- _subject.reset(0);
- _issuer.reset(0);
- throw CertificateEncodingException(__FILE__, __LINE__, errorToString(err));
- }
-
- _subject.retain(static_cast<CFDataRef>(CFDictionaryGetValue(attributes.get(), kSecAttrSubject)));
- _issuer.retain(static_cast<CFDataRef>(CFDictionaryGetValue(attributes.get(), kSecAttrIssuer)));
- CFDataRef serial = static_cast<CFDataRef>(CFDictionaryGetValue(attributes.get(), kSecAttrSerialNumber));
- ostringstream os;
- for(int i = 0; i < CFDataGetLength(serial); ++i)
- {
- int c = static_cast<int>(CFDataGetBytePtr(serial)[i]);
- if(i)
- {
- os << ' ';
- }
- os.fill('0');
- os.width(2);
- os << hex << c;
- }
- _serial = os.str();
- CFNumberRef version = static_cast<CFNumberRef>(CFDictionaryGetValue(attributes.get(), kSecAttrCertificateType));
- if(!CFNumberGetValue(version, kCFNumberIntType, &_version))
- {
- _version = -1;
- }
-}
-#endif