Revize 2c8b7911
Přidáno uživatelem Stanislav Král před téměř 4 roky(ů)
src/services/cryptography.py | ||
---|---|---|
2 | 2 |
import subprocess |
3 | 3 |
import time |
4 | 4 |
import random |
5 |
from typing import List |
|
5 | 6 |
|
6 | 7 |
from src.constants import CRL_CONFIG |
7 | 8 |
from src.model.certificate import Certificate |
... | ... | |
411 | 412 |
|
412 | 413 |
# openssl ca requires the .srl file to exists, therefore a dummy, unused file is created |
413 | 414 |
with TemporaryFile("serial.srl", "0") as serial_file, \ |
414 |
TemporaryFile("crl.conf", CRL_CONFIG % (index_file_path, serial_file)) as config_file, \ |
|
415 |
TemporaryFile("certificate.pem", cert.pem_data) as cert_file, \ |
|
416 |
TemporaryFile("private_key.pem", key.private_key) as key_file: |
|
417 |
|
|
415 |
TemporaryFile("crl.conf", CRL_CONFIG % (index_file_path, serial_file)) as config_file, \ |
|
416 |
TemporaryFile("certificate.pem", cert.pem_data) as cert_file, \ |
|
417 |
TemporaryFile("private_key.pem", key.private_key) as key_file: |
|
418 | 418 |
args = ["ca", "-config", config_file, "-gencrl", "-keyfile", key_file, "-cert", cert_file, "-outdir", "."] |
419 | 419 |
|
420 | 420 |
if key.password is not None and key.password != "": |
... | ... | |
437 | 437 |
Logger.debug("Function launched.") |
438 | 438 |
|
439 | 439 |
with TemporaryFile("certificate.pem", cert.pem_data) as ca_certificate, \ |
440 |
TemporaryFile("private_key.pem", key.private_key) as key_file, \ |
|
441 |
TemporaryFile("request.der", der_ocsp_request) as request_file: |
|
442 |
|
|
440 |
TemporaryFile("private_key.pem", key.private_key) as key_file, \ |
|
441 |
TemporaryFile("request.der", der_ocsp_request) as request_file: |
|
443 | 442 |
args = ["ocsp", "-index", index_path, "-CA", ca_certificate, "-rsigner", ca_certificate, "-rkey", key_file, |
444 | 443 |
"-reqin", request_file, "-respout", "-"] |
445 | 444 |
|
... | ... | |
448 | 447 |
|
449 | 448 |
return self.__run_for_output(args) |
450 | 449 |
|
450 |
def generate_pkcs_identity(self, cert_pem: str, cert_key_pem: str, identity_name: str, identity_passphrase: str, |
|
451 |
chain_of_trust_pems: List[str], cert_key_passphrase: str = None): |
|
452 |
""" |
|
453 |
Generates a PKCS12 identity of the given child certificate while including the given chain of trust. |
|
454 |
|
|
455 |
:param cert_pem: PEM of the certificate whose identity should be created |
|
456 |
:param cert_key_pem: PEM of the private key used to sign the certificate whose identity should be created |
|
457 |
:param identity_name: the name to be given to the identity created |
|
458 |
:param chain_of_trust_pems: list of PEMs representing certificates present in the chain of trust of the certificate |
|
459 |
whose identity should be created |
|
460 |
:param identity_passphrase: passphrase to be used when encrypting the identity |
|
461 |
:param cert_key_passphrase: passphrase of the key used to sign the certificate whose identity should be created |
|
462 |
:return: byte array containing the generated identity |
|
463 |
""" |
|
464 |
with TemporaryFile("cert_key.pem", cert_key_pem) as cert_key_pem_file: |
|
465 |
args = ["pkcs12", "-export", "-name", identity_name, "-in", "-", "-inkey", cert_key_pem_file, "-CAfile", |
|
466 |
"-", "-passout", f"pass:{identity_passphrase}", "-passin", f"pass:{cert_key_passphrase}"] |
|
467 |
return self.__run_for_output(args, |
|
468 |
proc_input=bytes(cert_pem + "".join(chain_of_trust_pems), |
|
469 |
encoding="utf-8")) |
|
470 |
|
|
451 | 471 |
|
452 | 472 |
class CryptographyException(Exception): |
453 | 473 |
|
tests/unit_tests/services/cryptography/generate_pkcs_identity_test.py | ||
---|---|---|
1 |
import subprocess |
|
2 |
|
|
3 |
import pytest |
|
4 |
|
|
5 |
from src.model.subject import Subject |
|
6 |
from src.services.cryptography import CryptographyException |
|
7 |
|
|
8 |
|
|
9 |
def test_generate_pkcs_identity(service): |
|
10 |
root_key = service.create_private_key() |
|
11 |
root_cert = service.create_sscrt(Subject(common_name="Foo"), root_key) |
|
12 |
|
|
13 |
inter_key = service.create_private_key() |
|
14 |
inter_cert = service.create_crt(Subject(common_name="Bar"), inter_key, root_cert, root_key) |
|
15 |
|
|
16 |
child_key = service.create_private_key() |
|
17 |
child_cert = service.create_crt(Subject(common_name="Baz"), child_key, inter_cert, inter_key) |
|
18 |
|
|
19 |
pkcs = service.generate_pkcs_identity(child_cert, child_key, "Baz Pkcs", "secret_pass", |
|
20 |
"".join([root_cert, inter_cert])) |
|
21 |
|
|
22 |
# print out the pkcs store in order to be able to check it |
|
23 |
pkcs_info = subprocess.check_output( |
|
24 |
["openssl", "pkcs12", "-info", "-in", "-", "-nodes", "-passin", "pass:secret_pass"], |
|
25 |
input=pkcs, |
|
26 |
stderr=subprocess.STDOUT).decode() |
|
27 |
|
|
28 |
assert child_cert in pkcs_info |
|
29 |
|
|
30 |
assert "-----BEGIN PRIVATE KEY-----" in pkcs_info |
|
31 |
assert root_cert in pkcs_info |
|
32 |
assert inter_cert in pkcs_info |
|
33 |
|
|
34 |
|
|
35 |
def test_generate_pkcs_identity_encrypted_key(service): |
|
36 |
root_key = service.create_private_key() |
|
37 |
root_cert = service.create_sscrt(Subject(common_name="Foo"), root_key) |
|
38 |
|
|
39 |
inter_key = service.create_private_key() |
|
40 |
inter_cert = service.create_crt(Subject(common_name="Bar"), inter_key, root_cert, root_key) |
|
41 |
|
|
42 |
# protect the child key with a passphrase |
|
43 |
child_key_passphrase = "keypass" |
|
44 |
child_key = service.create_private_key(passphrase=child_key_passphrase) |
|
45 |
child_cert = service.create_crt(Subject(common_name="Baz"), child_key, inter_cert, inter_key, child_key_passphrase) |
|
46 |
|
|
47 |
pkcs = service.generate_pkcs_identity(child_cert, child_key, "Baz Pkcs", "secret_pass", |
|
48 |
"".join([root_cert, inter_cert]), |
|
49 |
cert_key_passphrase=child_key_passphrase) |
|
50 |
|
|
51 |
# print out the pkcs store in order to be able to check it |
|
52 |
pkcs_info = subprocess.check_output( |
|
53 |
["openssl", "pkcs12", "-info", "-in", "-", "-nodes", "-passin", "pass:secret_pass"], |
|
54 |
input=pkcs, |
|
55 |
stderr=subprocess.STDOUT).decode() |
|
56 |
|
|
57 |
assert child_cert in pkcs_info |
|
58 |
|
|
59 |
assert "-----BEGIN PRIVATE KEY-----" in pkcs_info |
|
60 |
assert root_cert in pkcs_info |
|
61 |
assert inter_cert in pkcs_info |
|
62 |
|
|
63 |
|
|
64 |
def test_generate_pkcs_identity_encrypted_key_passphrase_not_provided(service): |
|
65 |
root_key = service.create_private_key() |
|
66 |
root_cert = service.create_sscrt(Subject(common_name="Foo"), root_key) |
|
67 |
|
|
68 |
inter_key = service.create_private_key() |
|
69 |
inter_cert = service.create_crt(Subject(common_name="Bar"), inter_key, root_cert, root_key) |
|
70 |
|
|
71 |
# protect the child key with a passphrase |
|
72 |
child_key_passphrase = "keypass" |
|
73 |
child_key = service.create_private_key(passphrase=child_key_passphrase) |
|
74 |
child_cert = service.create_crt(Subject(common_name="Baz"), child_key, inter_cert, inter_key, child_key_passphrase) |
|
75 |
|
|
76 |
with pytest.raises(CryptographyException): |
|
77 |
service.generate_pkcs_identity(child_cert, child_key, "Baz Pkcs", "secret_pass", |
|
78 |
"".join([root_cert, inter_cert])) |
|
79 |
|
|
80 |
|
|
81 |
def test_generate_pkcs_identity_encrypted_key_incorrect_passphrase(service): |
|
82 |
root_key = service.create_private_key() |
|
83 |
root_cert = service.create_sscrt(Subject(common_name="Foo"), root_key) |
|
84 |
|
|
85 |
inter_key = service.create_private_key() |
|
86 |
inter_cert = service.create_crt(Subject(common_name="Bar"), inter_key, root_cert, root_key) |
|
87 |
|
|
88 |
# protect the child key with a passphrase |
|
89 |
child_key_passphrase = "keypass" |
|
90 |
child_key = service.create_private_key(passphrase=child_key_passphrase) |
|
91 |
child_cert = service.create_crt(Subject(common_name="Baz"), child_key, inter_cert, inter_key, child_key_passphrase) |
|
92 |
|
|
93 |
with pytest.raises(CryptographyException): |
|
94 |
service.generate_pkcs_identity(child_cert, child_key, "Baz Pkcs", "secret_pass", |
|
95 |
"".join([root_cert, inter_cert]), cert_key_passphrase="passkey") |
Také k dispozici: Unified diff
Re #8708 - Implemented a new method in the CryptographyService that allows the caller to create a PKCS12 identity of a certificate and it's chain of trust
Covered the new method with unit tests.