aboutsummaryrefslogtreecommitdiff
path: root/src/main/model/pki/cert/Certificate.java
blob: f9d61bbafab3ddf1ce1a0f4029f347ec1c390fbd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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.
 * <pre>
 *    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},
 *    ... }
 * </pre>
 * <p>
 * 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 <pre>signature</pre>.
     */
    @Assoc(partOf = true)
    private final TbsCertificate certificate;

    /**
     * The algorithm used for <pre>signature</pre>.
     */
    @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;
    }
}