diff options
Diffstat (limited to 'Swiften/TLS/SecureTransport/SecureTransportCertificate.mm')
-rw-r--r-- | Swiften/TLS/SecureTransport/SecureTransportCertificate.mm | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm b/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm new file mode 100644 index 0000000..3b4e00f --- /dev/null +++ b/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/TLS/SecureTransport/SecureTransportCertificate.h> + +#include <boost/numeric/conversion/cast.hpp> + +#include <Cocoa/Cocoa.h> +#include <Security/Security.h> + +#include <Swiften/Base/Log.h> + +namespace { + +template <typename T, typename S> +T bridge_cast(S source) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" + return (__bridge T)(source); +#pragma clang diagnostic pop +} + +} + +namespace Swift { + +SecureTransportCertificate::SecureTransportCertificate(SecCertificateRef certificate) { + assert(certificate); + CFRetain(certificate); + certificateHandle_ = boost::shared_ptr<SecCertificate>(certificate, CFRelease); + parse(); +} + + +SecureTransportCertificate::SecureTransportCertificate(const ByteArray& der) { + CFDataRef derData = CFDataCreateWithBytesNoCopy(NULL, der.data(), static_cast<CFIndex>(der.size()), NULL); + SecCertificateRef certificate = SecCertificateCreateWithData(NULL, derData); + if (certificate) { + certificateHandle_ = boost::shared_ptr<SecCertificate>(certificate, CFRelease); + parse(); + } +} + +SecureTransportCertificate::~SecureTransportCertificate() { + +} + +#define NS2STDSTRING(a) (a == nil ? std::string() : std::string([a cStringUsingEncoding:NSUTF8StringEncoding])) + + +void SecureTransportCertificate::parse() { + assert(certificateHandle_); + CFErrorRef error = NULL; + + // The SecCertificateCopyValues function is not part of the iOS Secure Transport API. + CFDictionaryRef valueDict = SecCertificateCopyValues(certificateHandle_.get(), 0, &error); + if (error) { + CFRelease(error); + } + else { + // Handle subject. + CFStringRef subject = SecCertificateCopySubjectSummary(certificateHandle_.get()); + if (subject) { + NSString* subjectStr = bridge_cast<NSString*>(subject); + subjectName_ = NS2STDSTRING(subjectStr); + CFRelease(subject); + } + + // Handle a single Common Name. + CFStringRef commonName; + OSStatus error = SecCertificateCopyCommonName(certificateHandle_.get(), &commonName); + if (!error) { + NSString* commonNameStr = bridge_cast<NSString*>(commonName); + commonNames_.push_back(NS2STDSTRING(commonNameStr)); + CFRelease(commonName); + } + + // Handle Subject Alternative Names + NSDictionary* certDict = bridge_cast<NSDictionary*>(valueDict); + NSDictionary* subjectAltNamesDict = certDict[@"2.5.29.17"][@"value"]; + + for (NSDictionary* entry in subjectAltNamesDict) { + if ([entry[@"label"] isEqualToString:[NSString stringWithUTF8String:ID_ON_XMPPADDR_OID]]) { + xmppAddresses_.push_back(NS2STDSTRING(entry[@"value"])); + } + else if ([entry[@"label"] isEqualToString:[NSString stringWithUTF8String:ID_ON_DNSSRV_OID]]) { + srvNames_.push_back(NS2STDSTRING(entry[@"value"])); + } + else if ([entry[@"label"] isEqualToString:@"DNS Name"]) { + dnsNames_.push_back(NS2STDSTRING(entry[@"value"])); + } + } + CFRelease(valueDict); + } +} + +std::string SecureTransportCertificate::getSubjectName() const { + return subjectName_; +} + +std::vector<std::string> SecureTransportCertificate::getCommonNames() const { + return commonNames_; +} + +std::vector<std::string> SecureTransportCertificate::getSRVNames() const { + return srvNames_; +} + +std::vector<std::string> SecureTransportCertificate::getDNSNames() const { + return dnsNames_; +} + +std::vector<std::string> SecureTransportCertificate::getXMPPAddresses() const { + return xmppAddresses_; +} + +ByteArray SecureTransportCertificate::toDER() const { + ByteArray der; + if (certificateHandle_) { + CFDataRef derData = SecCertificateCopyData(certificateHandle_.get()); + if (derData) { + try { + size_t dataSize = boost::numeric_cast<size_t>(CFDataGetLength(derData)); + der.resize(dataSize); + CFDataGetBytes(derData, CFRangeMake(0,CFDataGetLength(derData)), der.data()); + } catch (...) { + } + CFRelease(derData); + } + } + return der; +} + +} |