3 # Given PEM encoded X.509 certificates Issuer and Subscriber,
4 # outputs the urlsafe base64 encoding of the SHA256 hash of
5 # the Issuer's SubjectPublicKeyInfo, and the ascii hex encoding
6 # of the Subscriber's serial number.
11 from cryptography
import x509
12 from cryptography
.hazmat
.primitives
import serialization
13 from cryptography
.hazmat
.primitives
import hashes
16 def uint_to_serial_bytes(a
):
17 # Encode the non-negative integer |a| as a DER integer without the leading
18 # tag and length prefix. The DER encoding of |a| is the shortest octet
19 # string that encodes |a| in big endian two's complement form.
22 # Since |a| is non-negative, the shortest bit string that encodes it in
23 # big-endian two's complement form has a leading 0 bit. Positive python
24 # integers have a `bit_length` method that gives the index of the leading 1
25 # bit. The minimal two's complement bit length is one more than this.
27 # NB: Python defines |int(0).bit_length() == 0|. The other cases are more
28 # intuitive; for integers x and k with x >= 0 and k > 0 with 2**k > x we
29 # have |int(2**k + x).bit_length() == k+1|.
30 bit_len
= 1 + a
.bit_length()
31 byte_len
= (bit_len
+ 7) // 8
32 return a
.to_bytes(byte_len
, byteorder
="big", signed
=False)
35 if len(sys
.argv
) != 3:
36 print(f
"Usage: {sys.argv[0]} <path to issuer cert> <path to subscriber cert>")
39 with
open(sys
.argv
[1], "r") as f
:
40 issuer
= x509
.load_pem_x509_certificate(f
.read().encode("utf-8"), backend
=None)
42 with
open(sys
.argv
[2], "r") as f
:
43 subscriber
= x509
.load_pem_x509_certificate(f
.read().encode("utf-8"), backend
=None)
45 assert issuer
.subject
.public_bytes() == subscriber
.issuer
.public_bytes()
47 issuer_spki
= issuer
.public_key().public_bytes(
48 format
=serialization
.PublicFormat
.SubjectPublicKeyInfo
,
49 encoding
=serialization
.Encoding
.DER
,
51 hasher
= hashes
.Hash(hashes
.SHA256(), backend
=None)
52 hasher
.update(issuer_spki
)
53 issuer_spki_hash
= hasher
.finalize()
55 subscriber_serial
= uint_to_serial_bytes(int(subscriber
.serial_number
))
57 print(base64
.urlsafe_b64encode(issuer_spki_hash
).decode("utf-8"))
58 print(subscriber_serial
.hex())