def generateKeyPair(self, keyName, params): """ Generate a pair of asymmetric keys. :param Name keyName: The name of the key pair. :param KeyParams params: The parameters of the key. """ if self.doesKeyExist(keyName, KeyClass.PUBLIC): raise SecurityException("Public key already exists") if self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException("Private key already exists") publicKeyDer = None privateKeyDer = None if params.getKeyType() == KeyType.RSA: key = RSA.generate(params.getKeySize()) publicKeyDer = key.publickey().exportKey(format='DER') privateKeyDer = key.exportKey(format='DER', pkcs=8) else: raise SecurityException("Unsupported key type") keyUri = keyName.toUri() publicKeyFilePath = self.nameTransform(keyUri, ".pub") privateKeyFilePath = self.nameTransform(keyUri, ".pri") with open(publicKeyFilePath, 'w') as keyFile: keyFile.write( Blob(base64.b64encode(publicKeyDer), False).toRawStr()) with open(privateKeyFilePath, 'w') as keyFile: keyFile.write( Blob(base64.b64encode(privateKeyDer), False).toRawStr()) os.chmod(publicKeyFilePath, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) os.chmod(privateKeyFilePath, stat.S_IRUSR)
def addCertificate(self, certificate): """ Add a certificate to the identity storage. :param IdentityCertificate certificate: The certificate to be added. This makes a copy of the certificate. """ certificateName = certificate.getName() keyName = certificate.getPublicKeyName() if not self.doesKeyExist(keyName): raise SecurityException( "No corresponding Key record for certificate! " + keyName.toUri() + " " + certificateName.toUri()) # Check if the certificate already exists. if self.doesCertificateExist(certificateName): raise SecurityException("Certificate has already been installed!") # Check if the public key of certificate is the same as the key record. keyBlob = self.getKey(keyName) if (keyBlob.isNull() or # Note: In Python, != should do a byte-by-byte comparison. keyBlob.toBuffer() != certificate.getPublicKeyInfo().getKeyDer().toBuffer()): raise SecurityException( "Certificate does not match the public key!") # Insert the certificate. # wireEncode returns the cached encoding if available. self._certificateStore[certificateName.toUri()] = ( certificate.wireEncode())
def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob """ keyURI = keyName.toUri() if not self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException( "FilePrivateKeyStorage.sign: private key doesn't exist") # Read the private key. base64Content = None with open(self.nameTransform(keyURI, ".pri")) as keyFile: base64Content = keyFile.read() pkcs8Der = base64.b64decode(base64Content) privateKey = TpmPrivateKey() try: privateKey.loadPkcs8(pkcs8Der) return privateKey.sign( Blob(data, False).toBytes(), digestAlgorithm) except Exception as ex: raise SecurityException("Error in sign: " + str(ex))
def getPublicKey(self, keyName): """ Get the public key with the keyName. :param Name keyName: The name of public key. :return: The public key. :rtype: PublicKey """ publicKey = self._getKey(keyName, KeyClass.PUBLIC) if publicKey == None: raise SecurityException("The requested public key [" + keyName.toUri() + "] does not exist in the OSX Keychain") exportedKey = None try: exportedKey = c_void_p() res = self._security.SecItemExport(publicKey, self._kSecFormatOpenSSL, 0, None, pointer(exportedKey)) if res != None: raise SecurityException( "Cannot export the requested public key from the OSX Keychain" ) blob = self._CFDataToBlob(exportedKey) return PublicKey(blob) finally: if publicKey != None: cf.CFRelease(publicKey) if exportedKey != None: cf.CFRelease(exportedKey)
def getCertificate(self, certificateName): """ Get a certificate from the identity storage. :param Name certificateName: The name of the requested certificate. :return: The requested certificate. :rtype: IdentityCertificate :raises SecurityException: if the certificate doesn't exist. """ cursor = self._database.cursor() cursor.execute( "SELECT certificate_data FROM Certificate WHERE cert_name=?", (certificateName.toUri(), )) row = cursor.fetchone() if row != None: (certData, ) = row cursor.close() certificate = IdentityCertificate() try: certificate.wireDecode(bytearray(certData)) except ValueError: raise SecurityException( "BasicIdentityStorage::getCertificate: The certificate cannot be decoded" ) return certificate else: cursor.close() raise SecurityException( "BasicIdentityStorage::getCertificate: The certificate does not exist" )
def generateKeyPair(self, keyName, params): """ Generate a pair of asymmetric keys. :param Name keyName: The name of the key pair. :param KeyParams params: The parameters of the key. """ if self.doesKeyExist(keyName, KeyClass.PUBLIC): raise SecurityException("Public key already exists") if self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException("Private key already exists") try: privateKey = TpmPrivateKey.generatePrivateKey(params) privateKeyDer = privateKey.toPkcs8().toBytes() publicKeyDer = privateKey.derivePublicKey().toBytes() except Exception as ex: raise SecurityException("Error in generatePrivateKey: " + str(ex)) keyUri = keyName.toUri() keyFilePathNoExtension = self.maintainMapping(keyUri) publicKeyFilePath = keyFilePathNoExtension + ".pub" privateKeyFilePath = keyFilePathNoExtension + ".pri" with open(publicKeyFilePath, 'w') as keyFile: keyFile.write(Common.base64Encode(publicKeyDer, True)) with open(privateKeyFilePath, 'w') as keyFile: keyFile.write(Common.base64Encode(privateKeyDer, True)) os.chmod(publicKeyFilePath, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) os.chmod(privateKeyFilePath, stat.S_IRUSR)
def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: The input byte buffer to sign. :type data: an array which implements the buffer protocol :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob :raises SecurityException: if can't find the private key with keyName. """ if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "MemoryPrivateKeyStorage.sign: Unsupported digest algorithm") # Find the private key. keyUri = keyName.toUri() if not keyUri in self._privateKeyStore: raise SecurityException( "MemoryPrivateKeyStorage: Cannot find private key " + keyUri) privateKey = self._privateKeyStore[keyUri] # Sign the hash of the data. if sys.version_info[0] == 2: # In Python 2.x, we need a str. Use Blob to convert data. data = Blob(data, False).toRawStr() signature = PKCS1_v1_5.new(privateKey.getPrivateKey()).sign( SHA256.new(data)) # Convert the string to a Blob. return Blob(bytearray(signature), False)
def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: The input byte buffer to sign. :type data: an array which implements the buffer protocol :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob :raises SecurityException: if can't find the private key with keyName. """ # Find the private key. keyUri = keyName.toUri() if not keyUri in self._privateKeyStore: raise SecurityException( "MemoryPrivateKeyStorage: Cannot find private key " + keyUri) privateKey = self._privateKeyStore[keyUri] try: return privateKey.sign( Blob(data, False).toBytes(), digestAlgorithm) except Exception as ex: raise SecurityException("Error in sign: " + str(ex))
def generateKeyPair(self, keyName, params): """ Generate a pair of asymmetric keys. :param Name keyName: The name of the key pair. :param KeyParams params: The parameters of the key. """ if self.doesKeyExist(keyName, KeyClass.PUBLIC): raise SecurityException("keyName already exists") keyLabel = None attrDict = None cfKeySize = None publicKey = None privateKey = None try: keyNameUri = self._toInternalKeyName(keyName, KeyClass.PUBLIC) keyLabel = CFSTR(keyNameUri) attrDict = c_void_p(cf.CFDictionaryCreateMutable( None, 3, cf.kCFTypeDictionaryKeyCallBacks, None)) if params.getKeyType() == KeyType.RSA: keySize = params.getKeySize() elif params.getKeyType() == KeyType.EC: keySize = params.getKeySize() else: raise SecurityException("generateKeyPair: Unsupported key type ") cfKeySize = c_void_p(cf.CFNumberCreate( None, kCFNumberIntType, byref(c_int(keySize)))) cf.CFDictionaryAddValue( attrDict, self._kSecAttrKeyType, self._getAsymmetricKeyType(params.getKeyType())) cf.CFDictionaryAddValue( attrDict, self._kSecAttrKeySizeInBits, cfKeySize) cf.CFDictionaryAddValue( attrDict, self._kSecAttrLabel, keyLabel) publicKey = c_void_p() privateKey = c_void_p() res = self._security.SecKeyGeneratePair( attrDict, pointer(publicKey), pointer(privateKey)) if res != 0: raise SecurityException("Fail to create a key pair") finally: if keyLabel != None: cf.CFRelease(keyLabel) if attrDict != None: cf.CFRelease(attrDict) if cfKeySize != None: cf.CFRelease(cfKeySize) if publicKey != None: cf.CFRelease(publicKey) if privateKey != None: cf.CFRelease(privateKey)
def getKey(self, keyName): """ Get the public key DER blob from the identity storage. :param Name keyName: The name of the requested public key. :return: The DER Blob. :rtype: Blob :raises SecurityException: if the key doesn't exist. """ if keyName.size() == 0: raise SecurityException( "BasicIdentityStorage::getKey: Empty keyName") identityUri = keyName[:-1].toUri() keyId = keyName[-1].toEscapedString() cursor = self._database.cursor() cursor.execute( "SELECT public_key FROM Key WHERE identity_name=? AND key_identifier=?", (identityUri, keyId)) row = cursor.fetchone() if row != None: (keyData, ) = row cursor.close() return Blob(bytearray(keyData), False) else: cursor.close() raise SecurityException( "BasicIdentityStorage::getKey: The key does not exist")
def signByIdentity(self, target, identityName=None, wireFormat=None): """ Sign the target. If it is a Data object, set its signature. If it is an array, return a signature object. :param target: If this is a Data object, wire encode for signing, update its signature and key locator field and wireEncoding. If it is an array, sign it and return a Signature object. :type target: Data or an array which implements the buffer protocol :param Name identityName: (optional) The identity name for the key to use for signing. If omitted, infer the signing identity from the data packet name. :param wireFormat: (optional) A WireFormat object used to encode the input. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :return: The Signature object (only if the target is an array). :rtype: An object of a subclass of Signature """ if identityName == None: identityName = Name() if isinstance(target, Data): if identityName.size() == 0: inferredIdentity = self._policyManager.inferSigningIdentity( target.getName()) if inferredIdentity.size() == 0: signingCertificateName = self._identityManager.getDefaultCertificateName( ) else: signingCertificateName = \ self._identityManager.getDefaultCertificateNameForIdentity(inferredIdentity) else: signingCertificateName = \ self._identityManager.getDefaultCertificateNameForIdentity(identityName) if signingCertificateName.size() == 0: raise SecurityException("No qualified certificate name found!") if not self._policyManager.checkSigningPolicy( target.getName(), signingCertificateName): raise SecurityException( "Signing Cert name does not comply with signing policy") self._identityManager.signByCertificate(target, signingCertificateName, wireFormat) else: signingCertificateName = \ self._identityManager.getDefaultCertificateNameForIdentity(identityName) if signingCertificateName.size() == 0: raise SecurityException("No qualified certificate name found!") return self._identityManager.signByCertificate( target, signingCertificateName)
def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob """ keyURI = keyName.toUri() if not self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException( "FilePrivateKeyStorage.sign: private key doesn't exist") if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "FilePrivateKeyStorage.sign: Unsupported digest algorithm") # Read the private key. base64Content = None with open(self.nameTransform(keyURI, ".pri")) as keyFile: base64Content = keyFile.read() der = Blob(base64.b64decode(base64Content), False) # Decode the PKCS #8 key to get the algorithm OID. parsedNode = DerNode.parse(der.buf(), 0) pkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren() oidString = algorithmIdChildren[0].toVal() privateKey = serialization.load_der_private_key( der.toBytes(), password=None, backend=default_backend()) # Sign the data. data = Blob(data, False).toBytes() if (oidString == PublicKey.RSA_ENCRYPTION_OID or oidString == PublicKey.EC_ENCRYPTION_OID): if oidString == PublicKey.RSA_ENCRYPTION_OID: signer = privateKey.signer(padding.PKCS1v15(), hashes.SHA256()) else: signer = privateKey.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() return Blob(bytearray(signature), False) else: raise SecurityException( "FilePrivateKeyStorage.sign: Unrecognized private key type")
def generateKeyPair(self, keyName, params): """ Generate a pair of asymmetric keys. :param Name keyName: The name of the key pair. :param KeyParams params: The parameters of the key. """ if self.doesKeyExist(keyName, KeyClass.PUBLIC): raise SecurityException("Public key already exists") if self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException("Private key already exists") publicKeyDer = None privateKeyDer = None if (params.getKeyType() == KeyType.RSA or params.getKeyType() == KeyType.ECDSA): if params.getKeyType() == KeyType.RSA: privateKey = rsa.generate_private_key( public_exponent=65537, key_size=params.getKeySize(), backend=default_backend()) else: privateKey = ec.generate_private_key( PrivateKeyStorage.getEcCurve(params.getKeySize()), default_backend()) publicKeyDer = privateKey.public_key().public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo) privateKeyDer = privateKey.private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()) else: raise SecurityException("Unsupported key type") keyUri = keyName.toUri() keyFilePathNoExtension = self.maintainMapping(keyUri) publicKeyFilePath = keyFilePathNoExtension + ".pub" privateKeyFilePath = keyFilePathNoExtension + ".pri" with open(publicKeyFilePath, 'w') as keyFile: keyFile.write( Blob(base64.b64encode(publicKeyDer), False).toRawStr()) with open(privateKeyFilePath, 'w') as keyFile: keyFile.write( Blob(base64.b64encode(privateKeyDer), False).toRawStr()) os.chmod(publicKeyFilePath, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) os.chmod(privateKeyFilePath, stat.S_IRUSR)
def signWithHmacWithSha256(target, key, wireFormat = None): """ Wire encode the target, compute an HmacWithSha256 and update the signature value. Note: This method is an experimental feature. The API may change. :param target: If this is a Data object, update its signature and wire encoding. :type target: Data :param Blob key: The key for the HmacWithSha256. :param wireFormat: (optional) The WireFormat for calling encodeData, etc., or WireFormat.getDefaultWireFormat() if omitted. :type wireFormat: A subclass of WireFormat """ if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() if isinstance(target, Data): data = target # Encode once to get the signed portion. encoding = data.wireEncode(wireFormat) signer = hmac.HMAC(key.toBytes(), hashes.SHA256(), backend = default_backend()) signer.update(encoding.toSignedBytes()) data.getSignature().setSignature( Blob(bytearray(signer.finalize()), False)) else: raise SecurityException("signWithHmacWithSha256: Unrecognized target type")
def addKey(self, keyName, keyType, publicKeyDer): """ Add a public key to the identity storage. :param Name keyName: The name of the public key to be added. :param keyType: Type of the public key to be added. :type keyType: int from KeyType :param Blob publicKeyDer: A blob of the public key DER to be added. """ if self.doesKeyExist(keyName): raise SecurityException("A key with the same name already exists!") identityName = keyName.getPrefix(-1) identityUri = identityName.toUri() makeDefault = 0 if not self.doesIdentityExist(identityName): self.addIdentity(identityName) makeDefault = 1 keyId = keyName.get(-1).toEscapedString() keyBuffer = buffer(bytearray (publicKeyDer.buf())) cursor = self._database.cursor() cursor.execute("INSERT INTO Key VALUES(?,?,?,?,?, ?)", (identityUri, keyId, keyType, keyBuffer, makeDefault, 1)) self._database.commit() cursor.close()
def setDefaultIdentity(self, identityName): """ Set the default identity. If the identityName does not exist, raises a SecurityException. :param Name identityName: The default identity name. """ if not self.doesIdentityExist(identityName): raise SecurityException("Identity does not exist") try: cursor = None currentDefault = self.getDefaultIdentity().toUri() except SecurityException: # no default, no need to remove default flag pass else: cursor = self._database.cursor() cursor.execute("UPDATE Identity SET default_identity=0 WHERE identity_name=?", (currentDefault,)) if cursor is None: cursor = self._database.cursor() # now set this identity as default cursor.execute("UPDATE Identity SET default_identity=1 WHERE identity_name=?", (identityName.toUri(), )) self._database.commit() cursor.close()
def addKey(self, keyName, keyType, publicKeyDer): """ Add a public key to the identity storage. Also call addIdentity to ensure that the identityName for the key exists. :param Name keyName: The name of the public key to be added. :param keyType: Type of the public key to be added. :type keyType: int from KeyType :param Blob publicKeyDer: A blob of the public key DER to be added. """ if keyName.size() == 0: return if self.doesKeyExist(keyName): raise SecurityException("A key with the same name already exists!") identityName = keyName[:-1] identityUri = identityName.toUri() self.addIdentity(identityName) keyId = keyName[-1].toEscapedString() keyBuffer = sqlite3.Binary(bytearray(publicKeyDer.buf())) cursor = self._database.cursor() cursor.execute( "INSERT INTO Key (identity_name, key_identifier, key_type, public_key) VALUES(?,?,?,?)", (identityUri, keyId, keyType, keyBuffer)) self._database.commit() cursor.close()
def getKeyType(self, keyName): """ Get the KeyType of the public key with the given keyName. :param Name keyName: The name of the requested public key. :return: The KeyType, for example KeyType.RSA. :rtype: an int from KeyType """ keyId = keyName.get(keyName.size() - 1).toEscapedString() identityName = keyName.getSubName(0, keyName.size() - 1) cursor = self._database.cursor() cursor.execute( "SELECT key_type FROM Key WHERE identity_name=? AND key_identifier=?", (identityName.toUri(), keyId)) row = cursor.fetchone() if row != None: (keyType, ) = row cursor.close() return keyType else: cursor.close() raise SecurityException( "Cannot get public key type because the keyName doesn't exist")
def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature, or an isNull() Blob pointer if signing fails. :rtype: Blob """ if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "FilePrivateKeyStorage.sign: Unsupported digest algorithm") der = self.getPrivateKey(keyName) privateKey = RSA.importKey(der.toRawStr()) # Sign the hash of the data. if sys.version_info[0] == 2: # In Python 2.x, we need a str. Use Blob to convert data. data = Blob(data, False).toRawStr() signature = PKCS1_v1_5.new(privateKey).sign(SHA256.new(data)) # Convert the string to a Blob. return Blob(bytearray(signature), False)
def getNewKeyName(self, identityName, useKsk): """ Generate a name for a new key belonging to the identity. :param Name identityName: The identity name. :param bool useKsk: If True, generate a KSK name, otherwise a DSK name. :return: The generated key name. :rtype: Name """ timestamp = math.floor(Common.getNowMilliseconds() / 1000.0) while timestamp <= self._lastTimestamp: # Make the timestamp unique. timestamp += 1 self._lastTimestamp = timestamp nowString = repr(timestamp).replace(".0", "") if useKsk: keyIdStr = "ksk-" + nowString else: keyIdStr = "dsk-" + nowString keyName = Name(identityName).append(keyIdStr) if self.doesKeyExist(keyName): raise SecurityException("Key name already exists") return keyName
def setDefaultCertificateNameForKey(self, keyName, certificateName): """ Set the default certificate name for the corresponding key :param Name keyName: not used :param Name certificateName: The certificate name. """ if not self.doesCertificateExist(certificateName): raise SecurityException("Certificate does not exist") keyName = IdentityCertificate.certificateNameToPublicKeyName(certificateName) identityUri = keyName.getPrefix(-1).toUri() keyId = keyName.get(-1).toEscapedString() try: cursor = None currentDefault = self.getDefaultCertificateNameForKey(keyName) except SecurityException: pass else: cursor = self._database.cursor() cursor.execute("UPDATE Certificate SET default_cert=0 WHERE cert_name=? AND identity_name=? AND key_identifier=?", (currentDefault.toUri(), identityUri, keyId)) if cursor is None: cursor = self._database.cursor() cursor.execute("UPDATE Certificate SET default_cert=1 WHERE cert_name=? AND identity_name=? AND key_identifier=?", (certificateName.toUri(), identityUri, keyId)) self._database.commit() cursor.close()
def verifySignature(signature, signedBlob, publicKeyDer): """ Check the type of signature and use the publicKeyDer to verify the signedBlob using the appropriate signature algorithm. :param Blob signature: An object of a subclass of Signature, e.g. Sha256WithRsaSignature. :param SignedBlob signedBlob: the SignedBlob with the signed portion to verify. :param Blob publicKeyDer: The DER-encoded public key used to verify the signature. This is ignored if the signature type does not require a public key. :return: True if the signature verifies, False if not. :rtype: bool :raises: SecurityException if the signature type is not recognized or if publicKeyDer can't be decoded. """ if isinstance(signature, Sha256WithRsaSignature): if publicKeyDer.isNull(): return False return PolicyManager._verifySha256WithRsaSignature( signature.getSignature(), signedBlob, publicKeyDer) elif isinstance(signature, Sha256WithEcdsaSignature): if publicKeyDer.isNull(): return False return PolicyManager._verifySha256WithEcdsaSignature( signature.getSignature(), signedBlob, publicKeyDer) elif isinstance(signature, DigestSha256Signature): return PolicyManager._verifyDigestSha256Signature( signature.getSignature(), signedBlob) else: raise SecurityException( "PolicyManager.verify: Signature type is unknown")
def _makeSignatureByCertificate(self, certificateName, digestAlgorithm): """ Return a new Signature object based on the signature algorithm of the public key with keyName (derived from certificateName). :param Name certificateName: The full certificate name. :param Array digestAlgorithm: Set digestAlgorithm[0] to the signature algorithm's digest algorithm, e.g. DigestAlgorithm.SHA256 . :return: The related public key name. :rtype: Signature """ keyName = IdentityCertificate.certificateNameToPublicKeyName( certificateName) publicKey = self._privateKeyStorage.getPublicKey(keyName) keyType = publicKey.getKeyType() if keyType == KeyType.RSA: signature = Sha256WithRsaSignature() digestAlgorithm[0] = DigestAlgorithm.SHA256 signature.getKeyLocator().setType(KeyLocatorType.KEYNAME) signature.getKeyLocator().setKeyName(certificateName.getPrefix(-1)) return signature elif keyType == KeyType.ECDSA: signature = Sha256WithEcdsaSignature() digestAlgorithm[0] = DigestAlgorithm.SHA256 signature.getKeyLocator().setType(KeyLocatorType.KEYNAME) signature.getKeyLocator().setKeyName(certificateName.getPrefix(-1)) return signature else: raise SecurityException("Key type is not recognized")
def _verifySha256WithEcdsaSignature(signature, signedBlob, publicKeyDer): """ Verify the ECDSA signature on the SignedBlob using the given public key. :param Blob signature: The signature bits. :param SignedBlob signedBlob: the SignedBlob with the signed portion to verify. :param Blob publicKeyDer: The DER-encoded public key used to verify the signature. :return: True if the signature verifies, False if not. :rtype: bool """ # Get the public key. publicKeyDerBytes = publicKeyDer.toBytes() try: publicKey = load_der_public_key( publicKeyDerBytes, backend = default_backend()) except: raise SecurityException("Cannot decode the ECDSA public key") # Verify. verifier = publicKey.verifier( signature.toBytes(), ec.ECDSA(hashes.SHA256())) verifier.update(signedBlob.toSignedBytes()) try: verifier.verify() return True except InvalidSignature: return False
def _lookupCertificateV2(self, certID, isPath): """ This looks up certificates specified as base64-encoded data or file names. These are cached by filename or encoding to avoid repeated reading of files or decoding. :return: The CertificateV2, or None if not found. :rtype: CertificateV2 """ if self._isSecurityV1: raise SecurityException( "lookupCertificateV2: For security v1, use lookupCertificate()" ) try: certUri = self._fixedCertificateCache[certID] except KeyError: if isPath: # load the certificate data (base64 encoded IdentityCertificate) cert = TrustAnchorRefreshManager.loadCertificateV2FromFile( certID) else: certData = b64decode(certID) cert = CertificateV2() cert.wireDecode(Blob(certData, False)) certUri = cert.getName()[:-1].toUri() self._fixedCertificateCache[certID] = certUri self._certificateCacheV2.insert(cert) else: cert = self._certificateCacheV2.find(Name(certUri)) return cert
def setDefaultKeyNameForIdentity(self, keyName, identityNameCheck=None): """ Set a key as the default key of an identity. The identity name is inferred from keyName. :param Name keyName: The name of the key. :param Name identityNameCheck: (optional) The identity name to check that the keyName contains the same identity name. If an empty name, it is ignored. """ keyId = keyName[-1].toEscapedString() identityName = keyName[:-1] if (not (identityNameCheck is None) and identityNameCheck.size() != 0 and not identityNameCheck.equals(identityName)): raise SecurityException( "Specified identity name does not match the key name") # Reset the previous default key. identityUri = identityName.toUri() cursor = self._database.cursor() cursor.execute( "UPDATE Key SET default_key=0 WHERE default_key=1 and identity_name=?", (identityUri, )) # Set the current default Key. cursor.execute( "UPDATE Key SET default_key=1 WHERE identity_name=? AND key_identifier=?", (identityUri, keyId)) self._database.commit() cursor.close()
def getDefaultCertificateNameForKey(self, keyName): """ Get the default certificate name for the specified key. :param Name keyName: The key name. :return: The default certificate name. :rtype: Name :raises SecurityException: if the default certificate name for the key name is not set. """ keyId = keyName[-1].toEscapedString() identityName = keyName[:-1] cursor = self._database.cursor() cursor.execute( "SELECT cert_name FROM Certificate WHERE identity_name=? AND key_identifier=? AND default_cert=1", (identityName.toUri(), keyId)) row = cursor.fetchone() if row != None: (certName, ) = row cursor.close() return Name(certName) else: cursor.close() raise SecurityException( "BasicIdentityStorage::getDefaultCertificateNameForKey: The default certificate for the key name is not defined" )
def getDefaultKeyNameForIdentity(self, identityName): """ Get the default key name for the specified identity. :param Name identityName: The identity name. :return: The default key name. :rtype: Name :raises SecurityException: if the default key name for the identity is not set. """ cursor = self._database.cursor() cursor.execute( "SELECT key_identifier FROM Key WHERE identity_name=? AND default_key=1", (identityName.toUri(), )) row = cursor.fetchone() if row != None: (keyName, ) = row cursor.close() return Name(identityName).append(keyName) else: cursor.close() raise SecurityException( "BasicIdentityStorage::getDefaultKeyNameForIdentity: The default key for the identity is not defined" )
def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature, or an isNull() Blob pointer if signing fails. :rtype: Blob """ keyURI = keyName.toUri() if not self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException( "FilePrivateKeyStorage.sign: private key doesn't exist") if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "FilePrivateKeyStorage.sign: Unsupported digest algorithm") # Read the private key. base64Content = None with open(self.nameTransform(keyURI, ".pri")) as keyFile: base64Content = keyFile.read() der = base64.b64decode(base64Content) if not type(der) is str: der = "".join(map(chr, der)) # The private key is generated by NFD which stores as PKCS #8. # This hack skips the PKCS #8 preamble because PyCryoto decodes as PKCS #1. # TODO: Use proper PKCS #8 decoding instead of this hack. pkcs8PreambleSize = 26 privateKey = RSA.importKey(der[pkcs8PreambleSize:]) # Sign the hash of the data. if sys.version_info[0] == 2: # In Python 2.x, we need a str. Use Blob to convert data. data = Blob(data, False).toRawStr() signature = PKCS1_v1_5.new(privateKey).sign(SHA256.new(data)) # Convert the string to a Blob. return Blob(bytearray(signature), False)
def addCertificate(self, certificate): """ Add a certificate to the identity storage. :param IdentityCertificate certificate: The certificate to be added. This makes a copy of the certificate. """ certificateName = certificate.getName() keyName = certificate.getPublicKeyName() if not self.doesKeyExist(keyName): raise SecurityException( "No corresponding Key record for certificate! " + keyName.toUri() + " " + certificateName.toUri()) # Check if the certificate already exists. if self.doesCertificateExist(certificateName): raise SecurityException("Certificate has already been installed!") keyId = keyName.get(-1).toEscapedString() identity = keyName[:-1] # Check if the public key of the certificate is the same as the key record. keyBlob = self.getKey(keyName) if (keyBlob.isNull() or not keyBlob.equals( certificate.getPublicKeyInfo().getKeyDer())): raise SecurityException("Certificate does not match public key") # Insert the certificate. signature = certificate.getSignature() signerName = KeyLocator.getFromSignature(signature).getKeyName() # Convert from milliseconds to seconds since 1/1/1970. notBefore = int(math.floor(certificate.getNotBefore() / 1000.0)) notAfter = int(math.floor(certificate.getNotAfter() / 1000.0)) encodedCert = sqlite3.Binary(bytearray(certificate.wireEncode().buf())) cursor = self._database.cursor() cursor.execute( "INSERT INTO Certificate (cert_name, cert_issuer, identity_name, key_identifier, not_before, not_after, certificate_data) " + "VALUES (?,?,?,?,?,?,?)", (certificateName.toUri(), signerName.toUri(), identity.toUri(), keyId, notBefore, notAfter, encodedCert)) self._database.commit() cursor.close()