def _load_certificate_data(certtype, buffer, result_typeid): """ Load a certificate with the supplied type and data. @param certtype: ignored @type certtype: - @param buffer: name of the KeyChain item to lookup @type buffer: L{str} @param result_typeid: The type to return (certificate or key) @type result_typeid: L{ffi.CFTypeID} @return: the certificate @rtype: L{X509} """ # First try to get the identity from the KeyChain data = CFDataRef.fromString(buffer) results = ffi.new("CFArrayRef *") err = security.SecItemImport(data.ref(), ffi.NULL, ffi.NULL, ffi.NULL, 0, ffi.NULL, ffi.NULL, results) if err != 0: raise Error("Could not load certificate data") results = CFArrayRef(results[0]).toList() # Try to find a SecCertificateRef for result in results: if result.instanceTypeId() == result_typeid: return result else: raise Error("No certificate in data")
def connect(self): """ Create the SecureTransport SSLContextRef object and initialize it. """ self.ctx = security.SSLCreateContext(ffi.NULL, security.kSSLClientSide if self.is_client else security.kSSLServerSide, security.kSSLStreamType) minVersion = None for option, minValue in ( (OP_NO_SSLv2, security.kSSLProtocol3), (OP_NO_SSLv3, security.kTLSProtocol1), (OP_NO_TLSv1, security.kTLSProtocol11), (OP_NO_TLSv1_1, security.kTLSProtocol12), (OP_NO_TLSv1_2, security.kTLSProtocol12), # TLS1.2 is the highest supported right now ): if option in self.context.options: minVersion = minValue if minVersion is not None: security.SSLSetProtocolVersionMin(self.ctx, minVersion) # Make sure we have a reference back to this L{Connection} in the SecureTransport callbacks self.connref = ffi.new("int *", self.engine_id) err = security.SSLSetConnection(self.ctx, ffi.cast("SSLConnectionRef", self.connref)) if err: self.shutdown() raise Error(err) # Setup the actual SecureTransport callbacks err = security.SSLSetIOFuncs(self.ctx, self._read, self._write) if err: self.shutdown() raise Error(err) # Must have a certificate identity if we are a server if not self.is_client and self.context.identity is None: self.shutdown() raise Error("No certificate") # Must have a peer name if we are a client if self.is_client and not self.context.peerName: self.shutdown() raise Error("No peer name set with client connection.") elif self.is_client: # Always set the client peer name for proper certificate validation err = security.SSLSetPeerDomainName(self.ctx, self.context.peerName, len(self.context.peerName)) if err: self.shutdown() raise Error(err) # Add the certificate if self.context.identity is not None: certs = CFArrayRef.fromList([self.context.identity]) err = security.SSLSetCertificate(self.ctx, certs.ref()) if err: self.shutdown() raise Error(err)
def load_keychain_identity(identity): """ Retrieve a SecIdentityRef from the KeyChain with a identity that exactly matches the passed in value. @param identity: identity value to match @type identity: L{str} @return: matched SecIdentityRef item or L{None} @rtype: L{CFObjectRef} """ # First try to load this from an identity preference cfsubject = CFStringRef.fromString(identity) secidentity = security.SecIdentityCopyPreferred(cfsubject.ref(), ffi.NULL, ffi.NULL) if secidentity != ffi.NULL: return CFObjectRef(secidentity) # Now iterate items to find a match match = CFDictionaryRef.fromDict({ CFStringRef.fromRef(security.kSecClass): CFStringRef.fromRef(security.kSecClassIdentity), CFStringRef.fromRef(security.kSecReturnRef): CFBooleanRef.fromBool(True), CFStringRef.fromRef(security.kSecReturnAttributes): CFBooleanRef.fromBool(True), CFStringRef.fromRef(security.kSecMatchLimit): CFStringRef.fromRef(security.kSecMatchLimitAll), }) result = ffi.new("CFTypeRef *") err = security.SecItemCopyMatching(match.ref(), result) if err != 0: return None result = CFArrayRef(result[0]) for item in result.toList(): if item[str(CFStringRef.fromRef(security.kSecAttrLabel))] == identity: secidentity = item[str(CFStringRef.fromRef(security.kSecValueRef))] break else: raise Error("Could not find Keychain identity: {}".format(identity)) return secidentity
def get_subject(self): """ Use Security.framework to extract the componentized SubjectName field and map OID values to strings and store in an L{X509Name} object. """ keys = CFArrayRef.fromList( [CFStringRef.fromRef(security.kSecOIDX509V1SubjectName)]) error = ffi.new("CFErrorRef *") values = security.SecCertificateCopyValues(self._x509.ref(), keys.ref(), error) if values == ffi.NULL: error = CFErrorRef(error[0]) raise Error("Unable to get certificate subject") values = CFDictionaryRef(values).toDict() value = values[str( CFStringRef.fromRef(security.kSecOIDX509V1SubjectName))] components = {} if value[str(CFStringRef.fromRef( security.kSecPropertyKeyType))] == str( CFStringRef.fromRef(security.kSecPropertyTypeSection)): for item in value[str( CFStringRef.fromRef(security.kSecPropertyKeyValue))]: if item[str(CFStringRef.fromRef( security.kSecPropertyKeyType))] == str( CFStringRef.fromRef( security.kSecPropertyTypeString)): v = item[str( CFStringRef.fromRef(security.kSecPropertyKeyValue))] k = OID2STR.get( item[str( CFStringRef.fromRef( security.kSecPropertyKeyLabel))], "Unknown") components[k] = v return X509Name("Subject Name", components)