package model.pki.cert; import annotations.Assoc; import model.asn1.ASN1Object; import model.asn1.BitString; import model.asn1.Tag; import model.asn1.exceptions.ParseException; import model.asn1.parsing.BytesReader; import model.pki.AlgorithmIdentifier; import java.util.Arrays; import java.util.Collection; import java.util.stream.Stream; /** * Represents an X.509 signed certificate. *
 *    Certificate ::= SIGNED{TBSCertificate}
 *
 *    ENCRYPTED{ToBeEnciphered} ::= BIT STRING (CONSTRAINED BY {
 *      -- shall be the result of applying an encipherment procedure
 *      -- to the BER-encoded octets of a value of -- ToBeEnciphered } )
 *
 *    HASH{ToBeHashed} ::= SEQUENCE {
 *      algorithmIdentifier AlgorithmIdentifier{{SupportedAlgorithms}},
 *      hashValue BIT STRING (CONSTRAINED BY {
 *          -- shall be the result of applying a hashing procedure to the DER-encoded
 *          -- octets of a value of -- ToBeHashed } ),
 *    ... }
 *
 *    ENCRYPTED-HASH{ToBeSigned} ::= BIT STRING (CONSTRAINED BY {
 *      -- shall be the result of applying a hashing procedure to the DER-encoded (see 6.2)
 *      -- octets of a value of -- ToBeSigned -- and then applying an encipherment procedure
 *      -- to those octets -- } )
 *
 *    SIGNATURE{ToBeSigned} ::= SEQUENCE {
 *      algorithmIdentifier AlgorithmIdentifier{{SupportedAlgorithms}},
 *      encrypted ENCRYPTED-HASH{ToBeSigned},
 *     ... }
 *
 *    SIGNED{ToBeSigned} ::= SEQUENCE {
 *      toBeSigned ToBeSigned,
 *      COMPONENTS OF SIGNATURE{ToBeSigned},
 *    ... }
 * 
*

* A certificate creates a binding between the proposed subject name and the public key. It is only valid once a trusted * CA signs it. Relying parties only need to trust a single trust anchor (the Root CA), and all of its issued certs are * trusted. This is done through the cert tree: each certificate contains the Issued By field, indicating the DN of the * upper level, all the way until the root CA, which is hard-coded in relying parties. */ public class Certificate extends ASN1Object { /** * All info of that cert, excluding the signature. * It will be signed, and the signature is in

signature
. */ @Assoc(partOf = true) private final TbsCertificate certificate; /** * The algorithm used for
signature
. */ @Assoc(partOf = true) private final AlgorithmIdentifier signatureAlgorithm; /** * The signature. */ @Assoc(partOf = true) private final BitString signature; /** * EFFECTS: Initialize the object with the given tag and parentTag, and info, signatureAlgorithm, and signature. * REQUIRES: The algorithm must match the signature. The fields must have correct tags as described in the class * specification (SEQUENCE, SEQUENCE, BIT STRING). */ public Certificate(Tag tag, Tag parentTag, final TbsCertificate certificate, final AlgorithmIdentifier signatureAlgorithm, final BitString signature) { super(tag, parentTag); this.certificate = certificate; this.signatureAlgorithm = signatureAlgorithm; this.signature = signature; } /** * EFFECTS: Parse input DER, without verifying the signature. * Throws {@link ParseException} if the input is invalid: * - Any fields missing * - Any fields having an incorrect tag (as seen in the ASN.1 definition) * - Any fields with encoding instructions that violate implicit / explicit encoding rules * - Other issues found during parsing the object, like early EOF (see {@link ASN1Object}) * MODIFIES: this, encoded */ public Certificate(BytesReader encoded, boolean hasParentTag) throws ParseException { super(encoded, hasParentTag); this.certificate = new TbsCertificate(encoded, false); this.certificate.getTag().enforce(TAG_SEQUENCE); this.signatureAlgorithm = new AlgorithmIdentifier(encoded, false); this.signatureAlgorithm.getTag().enforce(TAG_SEQUENCE); this.signature = new BitString(encoded, false); this.signature.getTag().enforce(BitString.TAG); } /** * EFFECT: Encode that sequence into an ordered array of bytes, following the class specification. */ @Override public Byte[] encodeValueDER() { return Stream.of(Arrays.asList(certificate.encodeDER()), Arrays.asList(signatureAlgorithm.encodeDER()), Arrays.asList(signature.encodeDER())) .flatMap(Collection::stream) .toArray(Byte[]::new); } public TbsCertificate getCertificate() { return certificate; } public AlgorithmIdentifier getSignatureAlgorithm() { return signatureAlgorithm; } public BitString getSignature() { return signature; } }