676 lines
23 KiB
Python
676 lines
23 KiB
Python
# This file is dual licensed under the terms of the Apache License, Version
|
|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
|
# for complete details.
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from cryptography import x509
|
|
from cryptography.exceptions import _Reasons
|
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
from cryptography.hazmat.primitives.asymmetric import ed25519
|
|
from cryptography.hazmat.primitives.serialization import pkcs7
|
|
|
|
from .utils import load_vectors_from_file
|
|
from ...utils import raises_unsupported_algorithm
|
|
|
|
|
|
class TestPKCS7Loading(object):
|
|
def test_load_invalid_der_pkcs7(self):
|
|
with pytest.raises(ValueError):
|
|
pkcs7.load_der_pkcs7_certificates(b"nonsense")
|
|
|
|
def test_load_invalid_pem_pkcs7(self):
|
|
with pytest.raises(ValueError):
|
|
pkcs7.load_pem_pkcs7_certificates(b"nonsense")
|
|
|
|
def test_not_bytes_der(self):
|
|
with pytest.raises(TypeError):
|
|
pkcs7.load_der_pkcs7_certificates(38)
|
|
|
|
def test_not_bytes_pem(self):
|
|
with pytest.raises(TypeError):
|
|
pkcs7.load_pem_pkcs7_certificates(38)
|
|
|
|
def test_load_pkcs7_pem(self):
|
|
certs = load_vectors_from_file(
|
|
os.path.join("pkcs7", "isrg.pem"),
|
|
lambda pemfile: pkcs7.load_pem_pkcs7_certificates(pemfile.read()),
|
|
mode="rb",
|
|
)
|
|
assert len(certs) == 1
|
|
assert certs[0].subject.get_attributes_for_oid(
|
|
x509.oid.NameOID.COMMON_NAME
|
|
) == [
|
|
x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, u"ISRG Root X1")
|
|
]
|
|
|
|
def test_load_pkcs7_der(self):
|
|
certs = load_vectors_from_file(
|
|
os.path.join("pkcs7", "amazon-roots.p7b"),
|
|
lambda derfile: pkcs7.load_der_pkcs7_certificates(derfile.read()),
|
|
mode="rb",
|
|
)
|
|
assert len(certs) == 2
|
|
assert certs[0].subject.get_attributes_for_oid(
|
|
x509.oid.NameOID.COMMON_NAME
|
|
) == [
|
|
x509.NameAttribute(
|
|
x509.oid.NameOID.COMMON_NAME, u"Amazon Root CA 3"
|
|
)
|
|
]
|
|
assert certs[1].subject.get_attributes_for_oid(
|
|
x509.oid.NameOID.COMMON_NAME
|
|
) == [
|
|
x509.NameAttribute(
|
|
x509.oid.NameOID.COMMON_NAME, u"Amazon Root CA 2"
|
|
)
|
|
]
|
|
|
|
def test_load_pkcs7_unsupported_type(self):
|
|
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION):
|
|
load_vectors_from_file(
|
|
os.path.join("pkcs7", "enveloped.pem"),
|
|
lambda pemfile: pkcs7.load_pem_pkcs7_certificates(
|
|
pemfile.read()
|
|
),
|
|
mode="rb",
|
|
)
|
|
|
|
|
|
# We have no public verification API and won't be adding one until we get
|
|
# some requirements from users so this function exists to give us basic
|
|
# verification for the signing tests.
|
|
def _pkcs7_verify(encoding, sig, msg, certs, options, backend):
|
|
sig_bio = backend._bytes_to_bio(sig)
|
|
if encoding is serialization.Encoding.DER:
|
|
p7 = backend._lib.d2i_PKCS7_bio(sig_bio.bio, backend._ffi.NULL)
|
|
elif encoding is serialization.Encoding.PEM:
|
|
p7 = backend._lib.PEM_read_bio_PKCS7(
|
|
sig_bio.bio,
|
|
backend._ffi.NULL,
|
|
backend._ffi.NULL,
|
|
backend._ffi.NULL,
|
|
)
|
|
else:
|
|
p7 = backend._lib.SMIME_read_PKCS7(sig_bio.bio, backend._ffi.NULL)
|
|
backend.openssl_assert(p7 != backend._ffi.NULL)
|
|
p7 = backend._ffi.gc(p7, backend._lib.PKCS7_free)
|
|
flags = 0
|
|
for option in options:
|
|
if option is pkcs7.PKCS7Options.Text:
|
|
flags |= backend._lib.PKCS7_TEXT
|
|
store = backend._lib.X509_STORE_new()
|
|
backend.openssl_assert(store != backend._ffi.NULL)
|
|
store = backend._ffi.gc(store, backend._lib.X509_STORE_free)
|
|
for cert in certs:
|
|
res = backend._lib.X509_STORE_add_cert(store, cert._x509)
|
|
backend.openssl_assert(res == 1)
|
|
if msg is None:
|
|
res = backend._lib.PKCS7_verify(
|
|
p7,
|
|
backend._ffi.NULL,
|
|
store,
|
|
backend._ffi.NULL,
|
|
backend._ffi.NULL,
|
|
flags,
|
|
)
|
|
else:
|
|
msg_bio = backend._bytes_to_bio(msg)
|
|
res = backend._lib.PKCS7_verify(
|
|
p7, backend._ffi.NULL, store, msg_bio.bio, backend._ffi.NULL, flags
|
|
)
|
|
backend.openssl_assert(res == 1)
|
|
|
|
|
|
def _load_cert_key():
|
|
key = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "ca_key.pem"),
|
|
lambda pemfile: serialization.load_pem_private_key(
|
|
pemfile.read(), None
|
|
),
|
|
mode="rb",
|
|
)
|
|
cert = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "ca.pem"),
|
|
loader=lambda pemfile: x509.load_pem_x509_certificate(pemfile.read()),
|
|
mode="rb",
|
|
)
|
|
return cert, key
|
|
|
|
|
|
class TestPKCS7Builder(object):
|
|
def test_invalid_data(self):
|
|
builder = pkcs7.PKCS7SignatureBuilder()
|
|
with pytest.raises(TypeError):
|
|
builder.set_data(u"not bytes")
|
|
|
|
def test_set_data_twice(self):
|
|
builder = pkcs7.PKCS7SignatureBuilder().set_data(b"test")
|
|
with pytest.raises(ValueError):
|
|
builder.set_data(b"test")
|
|
|
|
def test_sign_no_signer(self):
|
|
builder = pkcs7.PKCS7SignatureBuilder().set_data(b"test")
|
|
with pytest.raises(ValueError):
|
|
builder.sign(serialization.Encoding.SMIME, [])
|
|
|
|
def test_sign_no_data(self):
|
|
cert, key = _load_cert_key()
|
|
builder = pkcs7.PKCS7SignatureBuilder().add_signer(
|
|
cert, key, hashes.SHA256()
|
|
)
|
|
with pytest.raises(ValueError):
|
|
builder.sign(serialization.Encoding.SMIME, [])
|
|
|
|
def test_unsupported_hash_alg(self):
|
|
cert, key = _load_cert_key()
|
|
with pytest.raises(TypeError):
|
|
pkcs7.PKCS7SignatureBuilder().add_signer(
|
|
cert, key, hashes.SHA512_256()
|
|
)
|
|
|
|
def test_not_a_cert(self):
|
|
cert, key = _load_cert_key()
|
|
with pytest.raises(TypeError):
|
|
pkcs7.PKCS7SignatureBuilder().add_signer(
|
|
b"notacert", key, hashes.SHA256()
|
|
)
|
|
|
|
@pytest.mark.supported(
|
|
only_if=lambda backend: backend.ed25519_supported(),
|
|
skip_message="Does not support ed25519.",
|
|
)
|
|
def test_unsupported_key_type(self, backend):
|
|
cert, _ = _load_cert_key()
|
|
key = ed25519.Ed25519PrivateKey.generate()
|
|
with pytest.raises(TypeError):
|
|
pkcs7.PKCS7SignatureBuilder().add_signer(
|
|
cert, key, hashes.SHA256()
|
|
)
|
|
|
|
def test_sign_invalid_options(self):
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(b"test")
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
with pytest.raises(ValueError):
|
|
builder.sign(serialization.Encoding.SMIME, [b"invalid"])
|
|
|
|
def test_sign_invalid_encoding(self):
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(b"test")
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
with pytest.raises(ValueError):
|
|
builder.sign(serialization.Encoding.Raw, [])
|
|
|
|
def test_sign_invalid_options_text_no_detached(self):
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(b"test")
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
options = [pkcs7.PKCS7Options.Text]
|
|
with pytest.raises(ValueError):
|
|
builder.sign(serialization.Encoding.SMIME, options)
|
|
|
|
def test_sign_invalid_options_text_der_encoding(self):
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(b"test")
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
options = [
|
|
pkcs7.PKCS7Options.Text,
|
|
pkcs7.PKCS7Options.DetachedSignature,
|
|
]
|
|
with pytest.raises(ValueError):
|
|
builder.sign(serialization.Encoding.DER, options)
|
|
|
|
def test_sign_invalid_options_no_attrs_and_no_caps(self):
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(b"test")
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
options = [
|
|
pkcs7.PKCS7Options.NoAttributes,
|
|
pkcs7.PKCS7Options.NoCapabilities,
|
|
]
|
|
with pytest.raises(ValueError):
|
|
builder.sign(serialization.Encoding.SMIME, options)
|
|
|
|
def test_smime_sign_detached(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
options = [pkcs7.PKCS7Options.DetachedSignature]
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
sig = builder.sign(serialization.Encoding.SMIME, options)
|
|
sig_binary = builder.sign(serialization.Encoding.DER, options)
|
|
# We don't have a generic ASN.1 parser available to us so we instead
|
|
# will assert on specific byte sequences being present based on the
|
|
# parameters chosen above.
|
|
assert b"sha-256" in sig
|
|
# Detached signature means that the signed data is *not* embedded into
|
|
# the PKCS7 structure itself, but is present in the SMIME serialization
|
|
# as a separate section before the PKCS7 data. So we should expect to
|
|
# have data in sig but not in sig_binary
|
|
assert data in sig
|
|
_pkcs7_verify(
|
|
serialization.Encoding.SMIME, sig, data, [cert], options, backend
|
|
)
|
|
assert data not in sig_binary
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig_binary,
|
|
data,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_sign_byteslike(self):
|
|
data = bytearray(b"hello world")
|
|
cert, key = _load_cert_key()
|
|
options = [pkcs7.PKCS7Options.DetachedSignature]
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
sig = builder.sign(serialization.Encoding.SMIME, options)
|
|
assert bytes(data) in sig
|
|
|
|
def test_sign_pem(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
options = []
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
sig = builder.sign(serialization.Encoding.PEM, options)
|
|
_pkcs7_verify(
|
|
serialization.Encoding.PEM,
|
|
sig,
|
|
None,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
@pytest.mark.parametrize(
|
|
("hash_alg", "expected_value"),
|
|
[
|
|
(hashes.SHA1(), b"\x06\x05+\x0e\x03\x02\x1a"),
|
|
(hashes.SHA256(), b"\x06\t`\x86H\x01e\x03\x04\x02\x01"),
|
|
(hashes.SHA384(), b"\x06\t`\x86H\x01e\x03\x04\x02\x02"),
|
|
(hashes.SHA512(), b"\x06\t`\x86H\x01e\x03\x04\x02\x03"),
|
|
],
|
|
)
|
|
def test_sign_alternate_digests_der(
|
|
self, hash_alg, expected_value, backend
|
|
):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hash_alg)
|
|
)
|
|
options = []
|
|
sig = builder.sign(serialization.Encoding.DER, options)
|
|
assert expected_value in sig
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER, sig, None, [cert], options, backend
|
|
)
|
|
|
|
@pytest.mark.parametrize(
|
|
("hash_alg", "expected_value"),
|
|
[
|
|
(hashes.SHA1(), b"sha1"),
|
|
(hashes.SHA256(), b"sha-256"),
|
|
(hashes.SHA384(), b"sha-384"),
|
|
(hashes.SHA512(), b"sha-512"),
|
|
],
|
|
)
|
|
def test_sign_alternate_digests_detached(self, hash_alg, expected_value):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hash_alg)
|
|
)
|
|
options = [pkcs7.PKCS7Options.DetachedSignature]
|
|
sig = builder.sign(serialization.Encoding.SMIME, options)
|
|
# When in detached signature mode the hash algorithm is stored as a
|
|
# byte string like "sha-384".
|
|
assert expected_value in sig
|
|
|
|
def test_sign_attached(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
options = []
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
sig_binary = builder.sign(serialization.Encoding.DER, options)
|
|
# When not passing detached signature the signed data is embedded into
|
|
# the PKCS7 structure itself
|
|
assert data in sig_binary
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig_binary,
|
|
None,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_sign_binary(self, backend):
|
|
data = b"hello\nworld"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
options = []
|
|
sig_no_binary = builder.sign(serialization.Encoding.DER, options)
|
|
sig_binary = builder.sign(
|
|
serialization.Encoding.DER, [pkcs7.PKCS7Options.Binary]
|
|
)
|
|
# Binary prevents translation of LF to CR+LF (SMIME canonical form)
|
|
# so data should not be present in sig_no_binary, but should be present
|
|
# in sig_binary
|
|
assert data not in sig_no_binary
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig_no_binary,
|
|
None,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
assert data in sig_binary
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig_binary,
|
|
None,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_sign_smime_canonicalization(self, backend):
|
|
data = b"hello\nworld"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
options = []
|
|
sig_binary = builder.sign(serialization.Encoding.DER, options)
|
|
# LF gets converted to CR+LF (SMIME canonical form)
|
|
# so data should not be present in the sig
|
|
assert data not in sig_binary
|
|
assert b"hello\r\nworld" in sig_binary
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig_binary,
|
|
None,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_sign_text(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
options = [
|
|
pkcs7.PKCS7Options.Text,
|
|
pkcs7.PKCS7Options.DetachedSignature,
|
|
]
|
|
sig_pem = builder.sign(serialization.Encoding.SMIME, options)
|
|
# The text option adds text/plain headers to the S/MIME message
|
|
# These headers are only relevant in SMIME mode, not binary, which is
|
|
# just the PKCS7 structure itself.
|
|
assert b"text/plain" in sig_pem
|
|
# When passing the Text option the header is prepended so the actual
|
|
# signed data is this.
|
|
signed_data = b"Content-Type: text/plain\r\n\r\nhello world"
|
|
_pkcs7_verify(
|
|
serialization.Encoding.SMIME,
|
|
sig_pem,
|
|
signed_data,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_sign_no_capabilities(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
options = [pkcs7.PKCS7Options.NoCapabilities]
|
|
sig_binary = builder.sign(serialization.Encoding.DER, options)
|
|
# NoCapabilities removes the SMIMECapabilities attribute from the
|
|
# PKCS7 structure. This is an ASN.1 sequence with the
|
|
# OID 1.2.840.113549.1.9.15. It does NOT remove all authenticated
|
|
# attributes, so we verify that by looking for the signingTime OID.
|
|
|
|
# 1.2.840.113549.1.9.15 SMIMECapabilities as an ASN.1 DER encoded OID
|
|
assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x0f" not in sig_binary
|
|
# 1.2.840.113549.1.9.5 signingTime as an ASN.1 DER encoded OID
|
|
assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x05" in sig_binary
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig_binary,
|
|
None,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_sign_no_attributes(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
options = [pkcs7.PKCS7Options.NoAttributes]
|
|
sig_binary = builder.sign(serialization.Encoding.DER, options)
|
|
# NoAttributes removes all authenticated attributes, so we shouldn't
|
|
# find SMIMECapabilities or signingTime.
|
|
|
|
# 1.2.840.113549.1.9.15 SMIMECapabilities as an ASN.1 DER encoded OID
|
|
assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x0f" not in sig_binary
|
|
# 1.2.840.113549.1.9.5 signingTime as an ASN.1 DER encoded OID
|
|
assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x05" not in sig_binary
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig_binary,
|
|
None,
|
|
[cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_sign_no_certs(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA256())
|
|
)
|
|
|
|
options = []
|
|
sig = builder.sign(serialization.Encoding.DER, options)
|
|
assert sig.count(cert.public_bytes(serialization.Encoding.DER)) == 1
|
|
|
|
options = [pkcs7.PKCS7Options.NoCerts]
|
|
sig_no = builder.sign(serialization.Encoding.DER, options)
|
|
assert sig_no.count(cert.public_bytes(serialization.Encoding.DER)) == 0
|
|
|
|
def test_multiple_signers(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
rsa_key = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "rsa_key.pem"),
|
|
lambda pemfile: serialization.load_pem_private_key(
|
|
pemfile.read(), None
|
|
),
|
|
mode="rb",
|
|
)
|
|
rsa_cert = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "rsa_ca.pem"),
|
|
loader=lambda pemfile: x509.load_pem_x509_certificate(
|
|
pemfile.read()
|
|
),
|
|
mode="rb",
|
|
)
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA512())
|
|
.add_signer(rsa_cert, rsa_key, hashes.SHA512())
|
|
)
|
|
options = []
|
|
sig = builder.sign(serialization.Encoding.DER, options)
|
|
# There should be three SHA512 OIDs in this structure
|
|
assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x03") == 3
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig,
|
|
None,
|
|
[cert, rsa_cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_multiple_signers_different_hash_algs(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
rsa_key = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "rsa_key.pem"),
|
|
lambda pemfile: serialization.load_pem_private_key(
|
|
pemfile.read(), None
|
|
),
|
|
mode="rb",
|
|
)
|
|
rsa_cert = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "rsa_ca.pem"),
|
|
loader=lambda pemfile: x509.load_pem_x509_certificate(
|
|
pemfile.read()
|
|
),
|
|
mode="rb",
|
|
)
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA384())
|
|
.add_signer(rsa_cert, rsa_key, hashes.SHA512())
|
|
)
|
|
options = []
|
|
sig = builder.sign(serialization.Encoding.DER, options)
|
|
# There should be two SHA384 and two SHA512 OIDs in this structure
|
|
assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x02") == 2
|
|
assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x03") == 2
|
|
_pkcs7_verify(
|
|
serialization.Encoding.DER,
|
|
sig,
|
|
None,
|
|
[cert, rsa_cert],
|
|
options,
|
|
backend,
|
|
)
|
|
|
|
def test_add_additional_cert_not_a_cert(self, backend):
|
|
with pytest.raises(TypeError):
|
|
pkcs7.PKCS7SignatureBuilder().add_certificate(b"notacert")
|
|
|
|
def test_add_additional_cert(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
rsa_cert = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "rsa_ca.pem"),
|
|
loader=lambda pemfile: x509.load_pem_x509_certificate(
|
|
pemfile.read()
|
|
),
|
|
mode="rb",
|
|
)
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA384())
|
|
.add_certificate(rsa_cert)
|
|
)
|
|
options = []
|
|
sig = builder.sign(serialization.Encoding.DER, options)
|
|
assert (
|
|
sig.count(rsa_cert.public_bytes(serialization.Encoding.DER)) == 1
|
|
)
|
|
|
|
def test_add_multiple_additional_certs(self, backend):
|
|
data = b"hello world"
|
|
cert, key = _load_cert_key()
|
|
rsa_cert = load_vectors_from_file(
|
|
os.path.join("x509", "custom", "ca", "rsa_ca.pem"),
|
|
loader=lambda pemfile: x509.load_pem_x509_certificate(
|
|
pemfile.read()
|
|
),
|
|
mode="rb",
|
|
)
|
|
builder = (
|
|
pkcs7.PKCS7SignatureBuilder()
|
|
.set_data(data)
|
|
.add_signer(cert, key, hashes.SHA384())
|
|
.add_certificate(rsa_cert)
|
|
.add_certificate(rsa_cert)
|
|
)
|
|
options = []
|
|
sig = builder.sign(serialization.Encoding.DER, options)
|
|
assert (
|
|
sig.count(rsa_cert.public_bytes(serialization.Encoding.DER)) == 2
|
|
)
|