def test_ecdsa_verify(self): with open(os.path.join(fixtures_dir, 'message.txt'), 'rb') as f: original_data = f.read() with open(os.path.join(fixtures_dir, 'ecdsa_signature'), 'rb') as f: signature = f.read() public = asymmetric.load_public_key(os.path.join(fixtures_dir, 'keys/test-public-ec-named.key')) asymmetric.ecdsa_verify(public, signature, original_data, 'sha1')
def test_ecdsa_sign(self): original_data = b'This is data to sign' private = asymmetric.load_private_key(os.path.join(fixtures_dir, 'keys/test-ec-named.key')) public = asymmetric.load_public_key(os.path.join(fixtures_dir, 'keys/test-ec-named.crt')) signature = asymmetric.ecdsa_sign(private, original_data, 'sha1') self.assertIsInstance(signature, byte_cls) asymmetric.ecdsa_verify(public, signature, original_data, 'sha1')
def test_ec_generate(self): public, private = asymmetric.generate_pair('ec', curve='secp256r1') self.assertEqual('ec', public.algorithm) self.assertEqual('secp256r1', public.asn1.curve[1]) original_data = b'This is data to sign' signature = asymmetric.ecdsa_sign(private, original_data, 'sha1') self.assertIsInstance(signature, byte_cls) asymmetric.ecdsa_verify(public, signature, original_data, 'sha1')
def test_ecdsa_verify_fail_each_byte(self): with open(os.path.join(fixtures_dir, 'message.txt'), 'rb') as f: original_data = f.read() with open(os.path.join(fixtures_dir, 'ecdsa_signature'), 'rb') as f: original_signature = f.read() public = asymmetric.load_public_key(os.path.join(fixtures_dir, 'keys/test-public-ec-named.key')) for i in range(0, len(original_signature)): if i == 0: signature = b'\xab' + original_signature[1:] elif i == len(original_signature) - 1: signature = original_signature[0:-1] + b'\xab' else: signature = original_signature[0:i] + b'\xab' + original_signature[i+1:] with self.assertRaises(errors.SignatureError): asymmetric.ecdsa_verify(public, signature, original_data + b'1', 'sha1')
def test_ecdsa_p384_signverify(): LOGGER.info( 'Sign data with newly generated NIST P-384 key and verify result') setup_keys() ha = 'sha384' s = ecdsa.sign(pytest.p384, pytest.tbs_str) print('[{}]'.format(', '.join(hex(x) for x in list(s.signature)))) # Preparing an algoroithm pubkey_alg = keys.PublicKeyAlgorithm({ 'algorithm': keys.PublicKeyAlgorithmId(pytest.p384.algorithm), 'parameters': keys.ECDomainParameters(name='named', value=pytest.p384.curve) }) # Preparing a PublicKeyInfo pubkey_asn1 = core.BitString.load(pytest.p384.pkey) pubkey_info = keys.PublicKeyInfo({ 'algorithm': pubkey_alg, 'public_key': pubkey_asn1.cast(keys.ECPointBitString) }) # Load a public key into the oscrypto engine to using it in the verify function public = load_public_key(pubkey_info) # Assert wrong text with pytest.raises(SignatureError): ecdsa_verify(public, s.signature, pytest.tbs_str_fail, ha) # Assert wrong key with pytest.raises(SignatureError): # Preparing a PublicKeyInfo pubkey_asn1 = core.BitString.load(pytest.p384_fail.pkey) pubkey_info = keys.PublicKeyInfo({ 'algorithm': pubkey_alg, 'public_key': pubkey_asn1.cast(keys.ECPointBitString) }) # Load a public key into the oscrypto engine to using it in the verify function public = load_public_key(pubkey_info) ecdsa_verify(public, s.signature, pytest.tbs_str, ha)
def test_ecdsa_verify_fail_each_byte(self): with open(os.path.join(fixtures_dir, 'message.txt'), 'rb') as f: original_data = f.read() with open(os.path.join(fixtures_dir, 'ecdsa_signature'), 'rb') as f: original_signature = f.read() public = asymmetric.load_public_key( os.path.join(fixtures_dir, 'keys/test-public-ec-named.key')) for i in range(0, len(original_signature)): if i == 0: signature = b'\xab' + original_signature[1:] elif i == len(original_signature) - 1: signature = original_signature[0:-1] + b'\xab' else: signature = original_signature[ 0:i] + b'\xab' + original_signature[i + 1:] with self.assertRaises(errors.SignatureError): asymmetric.ecdsa_verify(public, signature, original_data + b'1', 'sha1')
def test_ec_generate(self): public, private = asymmetric.generate_pair('ec', curve='secp256r1') self.assertEqual('ec', public.algorithm) self.assertEqual('secp256r1', public.asn1.curve[1]) original_data = b'This is data to sign' signature = asymmetric.ecdsa_sign(private, original_data, 'sha1') self.assertIsInstance(signature, byte_cls) asymmetric.ecdsa_verify(public, signature, original_data, 'sha1') raw_public = asymmetric.dump_public_key(public) asymmetric.load_public_key(raw_public) raw_private = asymmetric.dump_private_key(private, None) asymmetric.load_private_key(raw_private, None) self.assertIsInstance(private.fingerprint, byte_cls) self.assertIsInstance(public.fingerprint, byte_cls) self.assertEqual(private.fingerprint, public.fingerprint)
def test_ecdsa(self): # A key we generated earlier self.session.create_domain_parameters(KeyType.EC, { Attribute.EC_PARAMS: encode_named_curve_parameters('secp256r1'), }, local=True)\ .generate_keypair() priv = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PRIVATE_KEY) signature = priv.sign(b'Data to sign', mechanism=Mechanism.ECDSA_SHA1) # Encode as ASN.1 for OpenSSL signature = encode_ecdsa_signature(signature) from oscrypto.asymmetric import load_public_key, ecdsa_verify pub = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PUBLIC_KEY) pub = load_public_key(encode_ec_public_key(pub)) ecdsa_verify(pub, signature, b'Data to sign', 'sha1')
def test_ecdsa_signverify(curve, hashname): key_object = objects.ECCKey(0xE100) pkey, _ = crypto.generate_pair(key_object, curve=curve) key_object_fail = objects.ECCKey(0xE101) pkey_fail, _ = crypto.generate_pair(key_object_fail, curve=curve) ha = hashname s = crypto.ecdsa_sign(key_object, tbs_str) print('[{}]'.format(', '.join(hex(x) for x in list(s.signature)))) # Preparing a PublicKeyInfo pubkey_info = keys.PublicKeyInfo.load(pkey) # Load a public key into the oscrypto engine to using it in the verify function public = load_public_key(pubkey_info) ecdsa_verify(public, s.signature, tbs_str, ha) # Assert wrong text with pytest.raises(SignatureError): ecdsa_verify(public, s.signature, tbs_str_fail, ha) # Assert wrong key with pytest.raises(SignatureError): # Preparing a PublicKeyInfo pubkey_info = keys.PublicKeyInfo.load(pkey_fail) # Load a public key into the oscrypto engine to using it in the verify function public = load_public_key(pubkey_info) ecdsa_verify(public, s.signature, tbs_str, ha)
from oscrypto import asymmetric from asn1crypto import pem, keys import os from .. import config root = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) assets = os.path.join(root, 'assets') pc_path = os.path.join(assets, 'Package Control.sublime-package') pc_sig_path = os.path.join(assets, 'Package Control.sublime-package.sig') public_key_pem = config.read('signing')['public_key'] public_key = asymmetric.load_public_key(public_key_pem.encode('ascii')) private_key_pem = config.read_secret('private_key') private_key = asymmetric.load_private_key(private_key_pem.encode('ascii'), None) with open(pc_sig_path, 'wb') as wf, open(pc_path, 'rb') as rf: pc_data = rf.read() sig = asymmetric.ecdsa_sign(private_key, pc_data, 'sha256') asymmetric.ecdsa_verify(public_key, sig, pc_data, 'sha256') wf.write(pem.armor('PACKAGE CONTROL SIGNATURE', sig)) print('Signature written to %s' % pc_sig_path)
def validate_ocsp_response(cert, issuer, ocsp_request_obj, ocsp_response_objs, current_time): #print(cert.ocsp_urls) # Just to see how many urls there are subject = cert['tbs_certificate']['subject'].native errors = {} warnings = {} lints_list = [] count = 0 lints = {} for (ocsp_url, ocsp_response_obj) in ocsp_response_objs: count += 1 lints['domain'] = subject['common_name'] lints['ocsp_url'] = ocsp_url lints['response_count'] = count #print(ocsp_response_obj.native) errors = {} warnings = {} if isinstance(ocsp_response_obj, urllib.error.HTTPError): errors['HTTPError'] = str(ocsp_response_obj) lints['errors'] = errors lints['warnings'] = warnings lints_list.append(lints) return lints_list if isinstance(ocsp_response_obj, ValueError): errors['ValueError'] = str(ocsp_response_obj) lints['errors'] = errors lints['warnings'] = warnings lints_list.append(lints) return lints_list if (ocsp_response_obj['response_status'].native == 'unauthorized'): errors['Unauthorized'] = 'Responder returned unauthorized' lints['errors'] = errors lints['warnings'] = warnings lints_list.append(lints) continue if (ocsp_response_obj['response_status'].native == 'malformed_request' ): errors['ResponseFailure'] = 'Responder returned malformed request' lints['errors'] = errors lints['warnings'] = warnings lints_list.append(lints) continue request_nonce = ocsp_request_obj.nonce_value #print (ocsp_response_obj.native) response_nonce = ocsp_response_obj.nonce_value if request_nonce and response_nonce and request_nonce.native != response_nonce.native: errors[ 'NonceVerificationFailure'] = 'Unable to verify OCSP response since the request and response nonces do not match' if ocsp_response_obj['response_status'].native != 'successful': errors['OCSPCheckFailure'] = 'OCSP check returned as failed' response_bytes = ocsp_response_obj['response_bytes'] if response_bytes['response_type'].native != 'basic_ocsp_response': errors[ 'ResponseTypeFailure'] = 'OCSP response is not Basic OCSP Response' parsed_response = response_bytes['response'].parsed tbs_response = parsed_response['tbs_response_data'] certificate_response = tbs_response['responses'][0] certificate_id = certificate_response['cert_id'] algo = certificate_id['hash_algorithm']['algorithm'].native certificate_issuer_name_hash = certificate_id[ 'issuer_name_hash'].native certificate_issuer_key_hash = certificate_id['issuer_key_hash'].native certificate_serial_number = certificate_id['serial_number'].native certificate_issuer_name_hash_from_file = getattr(cert.issuer, algo) certificate_issuer_key_hash_from_file = getattr( issuer.public_key, algo) certificate_serial_number_from_file = cert.serial_number if certificate_serial_number != certificate_serial_number_from_file: errors['CertificateSerialMismatchFailure'] = \ 'OCSP response certificate serial number does not match request certificate serial number' if certificate_issuer_key_hash != certificate_issuer_key_hash_from_file: errors[ 'IssuerKeyMismatchFailure'] = 'OCSP response issuer key hash does not match request certificate issuer key hash' if certificate_issuer_name_hash != certificate_issuer_name_hash_from_file: errors['IssuerNameHashMismatchFailure'] = \ 'OCSP response issuer name hash does not match request certificate issuer name hash' this_update_time = certificate_response['this_update'].native if current_time < this_update_time: errors[ 'ThisUpdateTimeError'] = 'OCSP reponse update time is from the future' if "next_update" not in certificate_response or certificate_response[ 'next_update'].native is None: warnings[ 'NextUpdateTimeMissing'] = 'OCSP response does not contain next update time' else: next_update_time = certificate_response['next_update'].native if current_time > next_update_time: errors[ 'NextUpdateTimeFailure'] = 'OCSP reponse next update time is in the past' registry = CertificateRegistry(trust_roots=[issuer]) if tbs_response['responder_id'].name == 'by_key': key_identifier = tbs_response['responder_id'].native signing_cert = registry.retrieve_by_key_identifier(key_identifier) elif tbs_response['responder_id'].name == 'by_name': signing_certs = registry.retrieve_by_name( tbs_response['responder_id'].chosen, None) if signing_certs is not None and len(signing_certs) > 0: signing_cert = signing_certs[0] else: signing_cert = None if signing_cert is None: errors[ 'SigningCetificateNotFoundFailure'] = 'OCSP response signing certificate not found' lints['errors'] = errors lints['warnings'] = warnings lints_list.append(lints) continue if issuer.issuer_serial != signing_cert.issuer_serial: if signing_cert_issuer.issuer_serial != issuer.issuer_serial: errors[ 'UnauthorizedSigningCertificateFailure'] = 'OCSP response signed by unauthorized certificate' extended_key_usage = signing_cert.extended_key_usage_value if 'ocsp_signing' not in extended_key_usage.native: errors['ExtendedKeyUsageExtensionValueFailure'] = \ 'OCSP response signing certificate is not the issuing certificate and it does not have value "ocsp_signing"\ for the extended key usage extension' sig_algo = parsed_response['signature_algorithm'].signature_algo hash_algo = parsed_response['signature_algorithm'].hash_algo try: check_cert = asymmetric.load_certificate(signing_cert) if sig_algo == 'rsassa_pkcs1v15': asymmetric.rsa_pkcs1v15_verify( check_cert, parsed_response['signature'].native, tbs_response.dump(), hash_algo) elif sig_algo == 'dsa': asymmetric.dsa_verify(check_cert, parsed_response['signature'].native, tbs_response.dump(), hash_algo) elif sig_algo == 'ecdsa': asymmetric.ecdsa_verify(check_cert, parsed_response['signature'].native, tbs_response.dump(), hash_algo) else: errors[ 'UnsupportedAlgorithmFailure'] = 'OCSP response signature uses unsupported algorithm' except (oscrypto.errors.SignatureError): errors[ 'SignatureVerificationFailure'] = 'OCSP response signature could not be verified' if certificate_response['cert_status'].name == 'revoked': revocation_data = certificate_response['cert_status'].chosen if revocation_data['revocation_reason'].native is None: errors[ 'CertificateValidityFailure'] = 'Certificate revoked due to unknown reason' else: errors[ 'CertificateValidityFailure'] = 'Certicate revoked due to ' + revocation_data[ 'revocation_reason'].human_friendly if 'certs' in parsed_response and parsed_response[ 'certs'].native != None: #TODO Check for legit certs pass # print(parsed_response['certs'].native) if len(errors) == 0: errors['NoFailure'] = 'No errors in OCSP response' if len(warnings) == 0: warnings['NoWarning'] = 'No warnings in OCSP response' lints['errors'] = errors lints['warnings'] = warnings lints_list.append(lints) return lints_list