diff options
author | Benoit Foucher <benoit@zeroc.com> | 2016-06-27 17:54:30 +0200 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2016-06-27 17:54:30 +0200 |
commit | c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7 (patch) | |
tree | 5cb64dfe155e5d2349efb6c7dc4b0f5b5284d44a /cpp/src/IceSSL/Certificate.cpp | |
parent | Fix Windows php build to restore nuget packages (diff) | |
download | ice-c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7.tar.bz2 ice-c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7.tar.xz ice-c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7.zip |
Refactored SSL and iAP transports, support for running SSL on top
of TCP/iAP/Bluetooth.
Diffstat (limited to 'cpp/src/IceSSL/Certificate.cpp')
-rwxr-xr-x[-rw-r--r--] | cpp/src/IceSSL/Certificate.cpp | 606 |
1 files changed, 516 insertions, 90 deletions
diff --git a/cpp/src/IceSSL/Certificate.cpp b/cpp/src/IceSSL/Certificate.cpp index 61597bdd0fe..5429a96b2e9 100644..100755 --- a/cpp/src/IceSSL/Certificate.cpp +++ b/cpp/src/IceSSL/Certificate.cpp @@ -15,6 +15,7 @@ #include <IceSSL/Util.h> #include <IceSSL/RFC2253.h> #include <Ice/Object.h> +#include <Ice/Base64.h> #if defined(ICE_USE_OPENSSL) # include <openssl/x509v3.h> @@ -42,12 +43,12 @@ extern "C" typedef void (*FreeFunc)(void*); #endif - using namespace std; using namespace Ice; using namespace IceSSL; #if defined(ICE_USE_SECURE_TRANSPORT) || defined(ICE_USE_SCHANNEL) + // // Map a certificate OID to its alias // @@ -80,7 +81,6 @@ const int certificateOIDSSize = sizeof(certificateOIDS) / sizeof(CertificateOID) #endif - #if defined(ICE_USE_SECURE_TRANSPORT) string @@ -98,29 +98,6 @@ certificateOIDAlias(const string& name) return name; } -// -// 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 -} - string escapeX509Name(const string& name) { @@ -149,6 +126,31 @@ escapeX509Name(const string& name) 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) { @@ -256,8 +258,158 @@ getX509String(SecCertificateRef cert, CFTypeRef key) return value; } -#elif defined(ICE_USE_SCHANNEL) +#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_WINRT) + +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) { @@ -294,9 +446,6 @@ loadCertificate(PCERT_SIGNED_CONTENT_INFO* cert, const string& file) loadCertificate(cert, &buffer[0], static_cast<DWORD>(buffer.size())); } -const Ice::Long TICKS_PER_MSECOND = 10000LL; -const Ice::Long MSECS_TO_EPOCH = 11644473600000LL; - IceUtil::Time filetimeToTime(FILETIME ftime) { @@ -419,6 +568,32 @@ certificateAltNames(CERT_INFO* certInfo, LPCSTR altNameOID) } return altNames; } +#else + +vector<pair<int, string> > +certificateAltNames(Windows::Security::Cryptography::Certificates::SubjectAlternativeNameInfo^ subAltNames) +{ + vector<pair<int, string> > altNames; + for (auto iter = subAltNames->EmailName->First(); iter->HasCurrent; iter->MoveNext()) + { + altNames.push_back(make_pair(AltNameEmail, IceUtil::wstringToString(iter->Current->Data()))); + } + for (auto iter = subAltNames->DnsName->First(); iter->HasCurrent; iter->MoveNext()) + { + altNames.push_back(make_pair(AltNameDNS, IceUtil::wstringToString(iter->Current->Data()))); + } + for (auto iter = subAltNames->Url->First(); iter->HasCurrent; iter->MoveNext()) + { + altNames.push_back(make_pair(AltNameURL, IceUtil::wstringToString(iter->Current->Data()))); + } + for (auto iter = subAltNames->IPAddress->First(); iter->HasCurrent; iter->MoveNext()) + { + altNames.push_back(make_pair(AltNAmeIP, IceUtil::wstringToString(iter->Current->Data()))); + } + return altNames; +} +#endif + #endif CertificateReadException::CertificateReadException(const char* file, int line, const string& r) : @@ -700,21 +875,25 @@ ParseException::ice_throw() const } #ifdef ICE_USE_OPENSSL -DistinguishedName::DistinguishedName(X509NAME* name) : - _rdns(RFC2253::parseStrict(convertX509NameToString(name))) +DistinguishedName::DistinguishedName(X509NAME* name) : _rdns(RFC2253::parseStrict(convertX509NameToString(name))) { unescape(); } #endif -DistinguishedName::DistinguishedName(const string& dn) : - _rdns(RFC2253::parseStrict(dn)) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) +DistinguishedName::DistinguishedName(CFDataRef data) : _rdns(ASN1Parser(data).parse()) { unescape(); } +#endif -DistinguishedName::DistinguishedName(const list<pair<string, string> >& rdns) : - _rdns(rdns) +DistinguishedName::DistinguishedName(const string& dn) : _rdns(RFC2253::parseStrict(dn)) +{ + unescape(); +} + +DistinguishedName::DistinguishedName(const list<pair<string, string> >& rdns) : _rdns(rdns) { unescape(); } @@ -810,7 +989,7 @@ PublicKey::~PublicKey() { # if defined(ICE_USE_SECURE_TRANSPORT) CFRelease(_key); -# else +# elif defined(ICE_USE_OPENSSL) EVP_PKEY_free(_key); # endif } @@ -827,9 +1006,6 @@ PublicKey::key() const // The caller is responsible for incrementing the reference count. // Certificate::Certificate(X509CertificateRef cert) : _cert(cert) -#ifdef ICE_USE_SCHANNEL - , _certInfo(0) -#endif { if(!_cert) { @@ -837,6 +1013,7 @@ Certificate::Certificate(X509CertificateRef cert) : _cert(cert) } #ifdef ICE_USE_SCHANNEL + _certInfo = 0; try { // @@ -856,13 +1033,28 @@ Certificate::Certificate(X509CertificateRef cert) : _cert(cert) throw; } #endif + +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + _subject = NULL; + _issuer = NULL; +#endif } Certificate::~Certificate() { if(_cert) { -#if defined(ICE_USE_SECURE_TRANSPORT) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + if(_subject) + { + CFRelease(_subject); + } + if(_issuer) + { + CFRelease(_issuer); + } + CFRelease(_cert); +#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS) CFRelease(_cert); #elif defined(ICE_USE_SCHANNEL) LocalFree(_cert); @@ -870,7 +1062,7 @@ Certificate::~Certificate() { LocalFree(_certInfo); } -#else +#elif defined(ICE_USE_OPENSSL) X509_free(_cert); #endif } @@ -880,12 +1072,20 @@ CertificatePtr Certificate::load(const string& file) { #if defined(ICE_USE_SECURE_TRANSPORT) - return ICE_MAKE_SHARED(Certificate, loadCertificate(file)); + 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); -#else +#elif defined(ICE_USE_OPENSSL) BIO *cert = BIO_new(BIO_s_file()); if(BIO_read_filename(cert, file.c_str()) <= 0) { @@ -901,16 +1101,45 @@ Certificate::load(const string& file) } BIO_free(cert); return ICE_MAKE_SHARED(Certificate, x); +#elif defined(ICE_OS_WINRT) + // TODO + return ICE_NULLPTR; +#else +# error "Unknown platform" #endif } CertificatePtr Certificate::decode(const string& encoding) { -#if defined(ICE_USE_SECURE_TRANSPORT) +#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) CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(encoding.c_str()), encoding.size(), kCFAllocatorNull); - SecExternalFormat format = kSecFormatUnknown; SecExternalItemType type = kSecItemTypeCertificate; @@ -929,14 +1158,13 @@ Certificate::decode(const string& encoding) SecKeychainItemRef item = (SecKeychainItemRef)CFArrayGetValueAtIndex(items, 0); CFRetain(item); CFRelease(items); - assert(SecCertificateGetTypeID() == CFGetTypeID(item)); return ICE_MAKE_SHARED(Certificate, (SecCertificateRef)item); #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); -#else +#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, NULL, NULL, NULL); if(x == NULL) @@ -946,6 +1174,11 @@ Certificate::decode(const string& encoding) } BIO_free(cert); return ICE_MAKE_SHARED(Certificate, x); +#elif defined(ICE_OS_WINRT) + // TODO + return ICE_NULLPTR; +#else +# error "Unknown platform" #endif } @@ -956,27 +1189,27 @@ Certificate::operator==(const Certificate& other) const return CFEqual(_cert, other._cert); #elif defined(ICE_USE_SCHANNEL) return CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, _certInfo, other._certInfo); -#else +#elif defined(ICE_USE_OPENSSL) return X509_cmp(_cert, other._cert) == 0; +#elif defined(ICE_OS_WINRT) + return _cert->Equals(other._cert); +#else +# error "Unknown platform" #endif } bool Certificate::operator!=(const Certificate& other) const { -#if defined(ICE_USE_SECURE_TRANSPORT) - return !CFEqual(_cert, other._cert); -#elif defined(ICE_USE_SCHANNEL) - return !CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, _certInfo, other._certInfo); -#else - return X509_cmp(_cert, other._cert) != 0; -#endif + return !operator==(other); } PublicKeyPtr Certificate::getPublicKey() const { -#if defined(ICE_USE_SECURE_TRANSPORT) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + return ICE_NULLPTR; // Not supported +#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS) SecKeyRef key; OSStatus err = SecCertificateCopyPublicKey(_cert, &key); if(err) @@ -986,8 +1219,12 @@ Certificate::getPublicKey() const return ICE_MAKE_SHARED(PublicKey, shared_from_this(), key); #elif defined(ICE_USE_SCHANNEL) return ICE_MAKE_SHARED(PublicKey, shared_from_this(), &_certInfo->SubjectPublicKeyInfo); -#else +#elif defined(ICE_USE_OPENSSL) return ICE_MAKE_SHARED(PublicKey, shared_from_this(), X509_get_pubkey(_cert)); +#elif defined(ICE_OS_WINRT) + return ICE_NULLPTR; // Not supported +#else +# error "Unknown platform" #endif } @@ -996,17 +1233,20 @@ 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 use SecTrustEvaluate - // and check a certificate against itself will always return - // that is valid. + // 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; - CFErrorRef error = 0; +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + initializeAttributes(); + cert->initializeAttributes(); + valid = CFEqual(_issuer, cert->_subject); +#else CFDataRef issuer = 0; CFDataRef subject = 0; - + CFErrorRef error = 0; try { issuer = SecCertificateCopyNormalizedIssuerContent(_cert, &error); @@ -1042,7 +1282,7 @@ Certificate::verify(const CertificatePtr& cert) const CFRelease(issuer); CFRelease(subject); - +#endif if(valid) { SecPolicyRef policy = 0; @@ -1107,8 +1347,12 @@ Certificate::verify(const CertificatePtr& cert) const bool result = CryptVerifyCertificateSignature(0, X509_ASN_ENCODING, buffer, length, cert->getPublicKey()->key()); LocalFree(buffer); return result; -#else +#elif defined(ICE_USE_OPENSSL) return X509_verify(_cert, cert->getPublicKey()->key()) > 0; +#elif defined(ICE_OS_WINRT) + return false; +#else +# error "Unknown platform" #endif } @@ -1123,7 +1367,15 @@ Certificate::verify(const PublicKeyPtr& key) const string Certificate::encode() const { -#if defined(ICE_USE_SECURE_TRANSPORT) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + UniqueRef<CFDataRef> c(SecCertificateCopyData(_cert)); + vector<unsigned char> data(CFDataGetBytePtr(c.get()), CFDataGetBytePtr(c.get()) + CFDataGetLength(c.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) CFDataRef exported; OSStatus err = SecItemExport(_cert, kSecFormatPEMSequence, kSecItemPemArmour, 0, &exported); if(err != noErr) @@ -1170,7 +1422,7 @@ Certificate::encode() const throw; } return s; -#else +#elif defined(ICE_USE_OPENSSL) BIO* out = BIO_new(BIO_s_mem()); int i = PEM_write_bio_X509_AUX(out, _cert); if(i <= 0) @@ -1183,9 +1435,25 @@ Certificate::encode() const string result = string(p->data, p->length); BIO_free(out); return result; +#elif defined(ICE_OS_WINRT) + 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], 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 { @@ -1206,8 +1474,13 @@ Certificate::getNotAfter() const return getX509Date(_cert, kSecOIDX509V1ValidityNotAfter); #elif defined(ICE_USE_SCHANNEL) return filetimeToTime(_certInfo->NotAfter); -#else +#elif defined(ICE_USE_OPENSSL) return ASMUtcTimeToIceUtilTime(X509_get_notAfter(_cert)); +#elif defined(ICE_OS_WINRT) + // Convert 100ns time from January 1, 1601 to ms from January 1, 1970 + return IceUtil::Time::milliSeconds(_cert->ValidTo.UniversalTime / TICKS_PER_MSECOND - MSECS_TO_EPOCH); +#else +# error "Unknown platform" #endif } @@ -1218,15 +1491,25 @@ Certificate::getNotBefore() const return getX509Date(_cert, kSecOIDX509V1ValidityNotBefore); #elif defined(ICE_USE_SCHANNEL) return filetimeToTime(_certInfo->NotBefore); -#else +#elif defined(ICE_USE_OPENSSL) return ASMUtcTimeToIceUtilTime(X509_get_notBefore(_cert)); +#elif defined(ICE_OS_WINRT) + // Convert 100ns time from January 1, 1601 to ms from January 1, 1970 + return IceUtil::Time::milliSeconds(_cert->ValidFrom.UniversalTime / TICKS_PER_MSECOND - MSECS_TO_EPOCH); +#else +# error "Unknown platform" #endif } +#endif + string Certificate::getSerialNumber() const { -#if defined(ICE_USE_SECURE_TRANSPORT) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + initializeAttributes(); + return _serial; +#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS) return getX509String(_cert, kSecOIDX509V1SerialNumber); #elif defined(ICE_USE_SCHANNEL) ostringstream os; @@ -1235,14 +1518,14 @@ Certificate::getSerialNumber() const unsigned char c = _certInfo->SerialNumber.pbData[i]; os.fill('0'); os.width(2); - os << hex << (int)c; + os << hex << static_cast<int>(c); if(i) { os << ' '; } } return IceUtilInternal::toUpper(os.str()); -#else +#elif defined(ICE_USE_OPENSSL) BIGNUM* bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(_cert), 0); char* dec = BN_bn2dec(bn); string result = dec; @@ -1250,31 +1533,40 @@ Certificate::getSerialNumber() const BN_free(bn); return result; +#elif defined(ICE_OS_WINRT) + 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 } -//string -//Certificate::getSigAlgName() const -//{ -//} - -//string -//Certificate::getSigAlgOID() const -//{ -//} - DistinguishedName Certificate::getIssuerDN() const { -#if defined(ICE_USE_SECURE_TRANSPORT) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + initializeAttributes(); + return _issuer ? DistinguishedName(_issuer) : DistinguishedName(""); +#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS) return getX509Name(_cert, kSecOIDX509V1IssuerName); #elif defined(ICE_USE_SCHANNEL) return DistinguishedName(certNameToString(&_certInfo->Issuer)); -#else +#elif defined(ICE_USE_OPENSSL) return DistinguishedName(RFC2253::parseStrict(convertX509NameToString(X509_get_issuer_name(_cert)))); +#elif defined(ICE_OS_WINRT) + return DistinguishedName(IceUtil::wstringToString(_cert->Issuer->Data())); +#else +# error "Unknown platform" #endif } +#if !defined(ICE_USE_SECURE_TRANSPORT_IOS) vector<pair<int, string> > Certificate::getIssuerAlternativeNames() { @@ -1282,23 +1574,45 @@ Certificate::getIssuerAlternativeNames() return getX509AltName(_cert, kSecOIDIssuerAltName); #elif defined(ICE_USE_SCHANNEL) return certificateAltNames(_certInfo, szOID_ISSUER_ALT_NAME2); -#else +#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_WINRT) + return vector<pair<int, string> >(); // Not supported +#else +# error "Unknown platform" #endif } +#endif DistinguishedName Certificate::getSubjectDN() const { -#if defined(ICE_USE_SECURE_TRANSPORT) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + initializeAttributes(); + if(_subject) + { + return DistinguishedName(_subject); + } + else + { + string s = "CN="; + s += fromCFString(UniqueRef<CFStringRef>(SecCertificateCopySubjectSummary(_cert)).get()); + return DistinguishedName(s); + } +#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS) return getX509Name(_cert, kSecOIDX509V1SubjectName); #elif defined(ICE_USE_SCHANNEL) return DistinguishedName(certNameToString(&_certInfo->Subject)); -#else +#elif defined(ICE_USE_OPENSSL) return DistinguishedName(RFC2253::parseStrict(convertX509NameToString(X509_get_subject_name(_cert)))); +#elif defined(ICE_OS_WINRT) + return DistinguishedName(IceUtil::wstringToString(_cert->Subject->Data())); +#else +# error "Unknown platform" #endif } +#if !defined(ICE_USE_SECURE_TRANSPORT_IOS) vector<pair<int, string> > Certificate::getSubjectAlternativeNames() { @@ -1306,20 +1620,32 @@ Certificate::getSubjectAlternativeNames() return getX509AltName(_cert, kSecOIDSubjectAltName); #elif defined(ICE_USE_SCHANNEL) return certificateAltNames(_certInfo, szOID_SUBJECT_ALT_NAME2); -#else +#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_WINRT) + return certificateAltNames(_cert->SubjectAlternativeName); +#else +# error "Unknown platform" #endif } +#endif int Certificate::getVersion() const { -#if defined(ICE_USE_SECURE_TRANSPORT) +#if defined(ICE_USE_SECURE_TRANSPORT_IOS) + initializeAttributes(); + return _version; +#elif defined(ICE_USE_SECURE_TRANSPORT_MACOS) return atoi(getX509String(_cert, kSecOIDX509V1Version).c_str()) - 1; #elif defined(ICE_USE_SCHANNEL) return _certInfo->dwVersion; -#else +#elif defined(ICE_USE_OPENSSL) return static_cast<int>(X509_get_version(_cert)); +#elif defined(ICE_OS_WINRT) + return -1; // Not supported +#else +# error "Unknown platform" #endif } @@ -1330,8 +1656,10 @@ Certificate::toString() const os << "serial: " << getSerialNumber() << "\n"; os << "issuer: " << string(getIssuerDN()) << "\n"; os << "subject: " << string(getSubjectDN()) << "\n"; +#if !defined(ICE_USE_SECURE_TRANSPORT_IOS) os << "notBefore: " << getNotBefore().toDateTime() << "\n"; os << "notAfter: " << getNotAfter().toDateTime(); +#endif return os.str(); } @@ -1340,3 +1668,101 @@ Certificate::getCert() const { return _cert; } + +#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 +{ + if(_subject) + { + return; + } + + // + // 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); + + CFMutableDictionaryRef query; + + query = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(query, kSecValueRef, _cert); + CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue); + CFDictionaryRef attributes; + OSStatus err; + if((err = SecItemAdd(query, (CFTypeRef*)&attributes)) == errSecDuplicateItem) + { + CFDictionarySetValue(query, kSecClass, kSecClassCertificate); + err = SecItemCopyMatching(query, (CFTypeRef*)&attributes); + } + else + { + CFRelease(query); + query = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(query, kSecClass, kSecClassCertificate); + CFDictionarySetValue(query, kSecValueRef, _cert); + err = SecItemDelete(query); + } + CFRelease(query); + if(err != noErr) + { + _subject = 0; + _issuer = 0; + return; + } + + _subject = (CFDataRef)CFDictionaryGetValue(attributes, kSecAttrSubject); + _issuer = (CFDataRef)CFDictionaryGetValue(attributes, kSecAttrIssuer); + CFDataRef serial = (CFDataRef)CFDictionaryGetValue(attributes, 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 = (CFNumberRef)CFDictionaryGetValue(attributes, kSecAttrCertificateType); + if(!CFNumberGetValue(version, kCFNumberIntType, &_version)) + { + _version = -1; + } + CFRetain(_subject); + CFRetain(_issuer); + + CFRelease(attributes); +} +#endif
\ No newline at end of file |