예제 #1
0
def sign_certificate_builder(
    session: PivSession,
    slot: SLOT,
    key_type: KEY_TYPE,
    builder: x509.CertificateBuilder,
    hash_algorithm: Type[hashes.HashAlgorithm] = hashes.SHA256,
) -> x509.Certificate:
    """Sign a Certificate."""
    dummy_key = _dummy_key(key_type)
    cert = builder.sign(dummy_key, hash_algorithm(), default_backend())

    sig = session.sign(
        slot,
        key_type,
        cert.tbs_certificate_bytes,
        hash_algorithm(),
        padding.PKCS1v15(),  # Only used for RSA
    )

    seq = Tlv.parse_list(Tlv.unpack(0x30, cert.public_bytes(Encoding.DER)))
    # Replace signature, add unused bits = 0
    seq[2] = Tlv(seq[2].tag, b"\0" + sig)
    # Re-assemble sequence
    der = Tlv(0x30, b"".join(seq))

    return x509.load_der_x509_certificate(der, default_backend())
예제 #2
0
 def _pack_tlvs(tlvs):
     header = b""
     body = b""
     for tlv in tlvs:
         header += tlv[: -tlv.length]
         body += tlv.value
     return Tlv(0x7F48, header) + Tlv(0x5F48, body)
예제 #3
0
        def test_read_write_certificate_as_object(self):
            with self.assertRaises(SystemExit):
                ykman_cli("piv", "read-object", hex(OBJECT_ID.AUTHENTICATION))

            cert = generate_self_signed_certificate()
            cert_bytes_der = cert.public_bytes(
                encoding=serialization.Encoding.DER)

            input_tlv = Tlv(0x70, cert_bytes_der) + Tlv(0x71, b"\0") + Tlv(
                0xFE, b"")

            ykman_cli(
                "piv",
                "write-object",
                hex(OBJECT_ID.AUTHENTICATION),
                "-",
                "-m",
                DEFAULT_MANAGEMENT_KEY,
                input=input_tlv,
            )

            output1 = ykman_cli.with_bytes_output(
                "piv", "read-object", hex(OBJECT_ID.AUTHENTICATION))
            output_cert_bytes = Tlv.parse_dict(output1)[0x70]
            self.assertEqual(output_cert_bytes, cert_bytes_der)

            output2 = ykman_cli.with_bytes_output(
                "piv",
                "export-certificate",
                hex(SLOT.AUTHENTICATION),
                "-",
                "--format",
                "DER",
            )
            self.assertEqual(output2, cert_bytes_der)
예제 #4
0
 def __init__(self, raw_data: bytes = Tlv(0x80)):
     data = Tlv.parse_dict(Tlv(raw_data).value)
     self._flags = struct.unpack(">B",
                                 data[0x81])[0] if 0x81 in data else None
     self.salt = data.get(0x82)
     self.pin_timestamp = struct.unpack(
         ">I", data[0x83]) if 0x83 in data else None
예제 #5
0
class KEY_SLOT(_KeySlot, Enum):  # noqa: N801
    SIG = _KeySlot("SIGNATURE", 1, 0xC1, 0xC7, 0xCE, 0xD6, Tlv(0xB6))
    ENC = _KeySlot("ENCRYPTION", 2, 0xC2, 0xC8, 0xCF, 0xD7, Tlv(0xB8))
    AUT = _KeySlot("AUTHENTICATION", 3, 0xC3, 0xC9, 0xD0, 0xD8, Tlv(0xA4))
    ATT = _KeySlot(
        "ATTESTATION", 4, 0xDA, 0xDB, 0xDD, 0xD9, Tlv(0xB6, Tlv(0x84, b"\x81"))
    )
예제 #6
0
def sign_csr_builder(
    session: PivSession,
    slot: SLOT,
    public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey],
    builder: x509.CertificateSigningRequestBuilder,
    hash_algorithm: Type[hashes.HashAlgorithm] = hashes.SHA256,
) -> x509.CertificateSigningRequest:
    """Sign a CSR."""
    key_type = KEY_TYPE.from_public_key(public_key)
    dummy_key = _dummy_key(key_type)
    csr = builder.sign(dummy_key, hash_algorithm(), default_backend())
    seq = Tlv.parse_list(Tlv.unpack(0x30, csr.public_bytes(Encoding.DER)))

    # Replace public key
    pub_format = (PublicFormat.PKCS1 if key_type.algorithm == ALGORITHM.RSA
                  else PublicFormat.SubjectPublicKeyInfo)
    dummy_bytes = dummy_key.public_key().public_bytes(Encoding.DER, pub_format)
    pub_bytes = public_key.public_bytes(Encoding.DER, pub_format)
    seq[0] = Tlv(seq[0].replace(dummy_bytes, pub_bytes))

    sig = session.sign(
        slot,
        key_type,
        seq[0],
        hash_algorithm(),
        padding.PKCS1v15(),  # Only used for RSA
    )

    # Replace signature, add unused bits = 0
    seq[2] = Tlv(seq[2].tag, b"\0" + sig)
    # Re-assemble sequence
    der = Tlv(0x30, b"".join(seq))

    return x509.load_der_x509_csr(der, default_backend())
예제 #7
0
 def _select_certificate(self, key_slot):
     self._app.send_apdu(
         0,
         INS.SELECT_DATA,
         3 - key_slot.index,
         0x04,
         Tlv(0, Tlv(0x60, Tlv(0x5C, b"\x7f\x21")))[1:],
     )
예제 #8
0
 def get_bytes(self) -> bytes:
     data = b""
     if self._flags is not None:
         data += Tlv(0x81, struct.pack(">B", self._flags))
     if self.salt is not None:
         data += Tlv(0x82, self.salt)
     if self.pin_timestamp is not None:
         data += Tlv(0x83, struct.pack(">I", self.pin_timestamp))
     return Tlv(0x80, data)
예제 #9
0
def generate_chuid() -> bytes:
    """Generates a CHUID (Cardholder Unique Identifier)."""
    # Non-Federal Issuer FASC-N
    # [9999-9999-999999-0-1-0000000000300001]
    FASC_N = (b"\xd4\xe7\x39\xda\x73\x9c\xed\x39\xce\x73\x9d\x83\x68" +
              b"\x58\x21\x08\x42\x10\x84\x21\xc8\x42\x10\xc3\xeb")
    # Expires on: 2030-01-01
    EXPIRY = b"\x32\x30\x33\x30\x30\x31\x30\x31"

    return (Tlv(0x30, FASC_N) + Tlv(0x34, os.urandom(16)) + Tlv(0x35, EXPIRY) +
            Tlv(0x3E) + Tlv(TAG_LRC))
예제 #10
0
 def _select_certificate(self, key_slot):
     data = Tlv(0x60, Tlv(0x5C, b"\x7f\x21"))
     if self.version <= (
             5, 4, 3):  # These use a non-standard byte in the command.
         data = b"\x06" + data  # 6 is the length of the data.
     self._app.send_apdu(
         0,
         INS.SELECT_DATA,
         3 - key_slot.index,
         0x04,
         data,
     )
예제 #11
0
    def test_tlv(self):
        self.assertEqual(Tlv(b"\xfe\6foobar"), Tlv(0xFE, b"foobar"))

        tlv1 = Tlv(b"\0\5hello")
        tlv2 = Tlv(0xFE, b"")
        tlv3 = Tlv(0x12, b"hi" * 200)

        self.assertEqual(b"\0\5hello", tlv1)
        self.assertEqual(b"\xfe\0", tlv2)
        self.assertEqual(b"\x12\x82\x01\x90" + b"hi" * 200, tlv3)

        self.assertEqual(b"\0\5hello\xfe\0\x12\x82\x01\x90" + b"hi" * 200,
                         tlv1 + tlv2 + tlv3)
예제 #12
0
 def _select_certificate(self, key_slot):
     try:
         require_version(self.version, (5, 2, 0))
         data: bytes = Tlv(0x60, Tlv(0x5C, b"\x7f\x21"))
         if self.version <= (5, 4, 3):
             # These use a non-standard byte in the command.
             data = b"\x06" + data  # 6 is the length of the data.
         self._app.send_apdu(
             0,
             INS.SELECT_DATA,
             3 - key_slot.indx,
             0x04,
             data,
         )
     except NotSupportedError:
         if key_slot == KEY_SLOT.AUT:
             return  # Older version still support AUT, which is the default slot.
         raise
예제 #13
0
def _get_key_template(key, key_slot, crt=False):
    def _pack_tlvs(tlvs):
        header = b""
        body = b""
        for tlv in tlvs:
            header += tlv[: -tlv.length]
            body += tlv.value
        return Tlv(0x7F48, header) + Tlv(0x5F48, body)

    values: Tuple[Tlv, ...]

    if isinstance(key, rsa.RSAPrivateKeyWithSerialization):
        rsa_numbers = key.private_numbers()
        ln = (key.key_size // 8) // 2

        e = Tlv(0x91, b"\x01\x00\x01")  # e=65537
        p = Tlv(0x92, int2bytes(rsa_numbers.p, ln))
        q = Tlv(0x93, int2bytes(rsa_numbers.q, ln))
        values = (e, p, q)
        if crt:
            dp = Tlv(0x94, int2bytes(rsa_numbers.dmp1, ln))
            dq = Tlv(0x95, int2bytes(rsa_numbers.dmq1, ln))
            qinv = Tlv(0x96, int2bytes(rsa_numbers.iqmp, ln))
            n = Tlv(0x97, int2bytes(rsa_numbers.public_numbers.n, 2 * ln))
            values += (dp, dq, qinv, n)

    elif isinstance(key, ec.EllipticCurvePrivateKeyWithSerialization):
        ec_numbers = key.private_numbers()
        ln = key.key_size // 8

        privkey = Tlv(0x92, int2bytes(ec_numbers.private_value, ln))
        values = (privkey,)

    elif _get_curve_name(key) in ("ed25519", "x25519"):
        privkey = Tlv(
            0x92, key.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
        )
        values = (privkey,)

    return Tlv(0x4D, key_slot.crt + _pack_tlvs(values))
    def test_read_write_certificate_as_object(self, ykman_cli):
        with pytest.raises(SystemExit):
            ykman_cli("piv", "objects", "export",
                      hex(OBJECT_ID.AUTHENTICATION), "-")

        cert = generate_self_signed_certificate()
        cert_bytes_der = cert.public_bytes(encoding=serialization.Encoding.DER)

        input_tlv = Tlv(0x70, cert_bytes_der) + Tlv(0x71, b"\0") + Tlv(
            0xFE, b"")

        ykman_cli(
            "piv",
            "objects",
            "import",
            hex(OBJECT_ID.AUTHENTICATION),
            "-",
            "-m",
            DEFAULT_MANAGEMENT_KEY,
            input=input_tlv,
        )

        output1 = ykman_cli("piv", "objects", "export",
                            hex(OBJECT_ID.AUTHENTICATION), "-").stdout_bytes
        output_cert_bytes = Tlv.parse_dict(output1)[0x70]
        assert output_cert_bytes == cert_bytes_der

        output2 = ykman_cli(
            "piv",
            "certificates",
            "export",
            hex(SLOT.AUTHENTICATION),
            "-",
            "--format",
            "DER",
        ).stdout_bytes
        assert output2 == cert_bytes_der
예제 #15
0
def generate_ccc() -> bytes:
    """Generates a CCC (Card Capability Container)."""
    return (Tlv(0xF0, b"\xa0\x00\x00\x01\x16\xff\x02" + os.urandom(14)) +
            Tlv(0xF1, b"\x21") + Tlv(0xF2, b"\x21") + Tlv(0xF3) +
            Tlv(0xF4, b"\x00") + Tlv(0xF5, b"\x10") + Tlv(0xF6) + Tlv(0xF7) +
            Tlv(0xFA) + Tlv(0xFB) + Tlv(0xFC) + Tlv(0xFD) + Tlv(TAG_LRC))
예제 #16
0
 def __init__(self, raw_data: bytes = Tlv(0x88)):
     data = Tlv.parse_dict(Tlv(raw_data).value)
     self.key = data.get(0x89)
예제 #17
0
 def get_bytes(self) -> bytes:
     data = b""
     if self.key is not None:
         data += Tlv(0x89, self.key)
     return Tlv(0x88, data)