summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/Certificate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceSSL/Certificate.cpp')
-rwxr-xr-x[-rw-r--r--]cpp/src/IceSSL/Certificate.cpp606
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