aboutsummaryrefslogtreecommitdiff
path: root/src/main/model/csr/CertificationRequestInfo.java
blob: 483481358ca93821de7d253892638391bab2d16b (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
132
133
134
135
package model.csr;

import annotations.Assoc;
import model.asn1.ASN1Object;
import model.asn1.Int;
import model.asn1.Tag;
import model.asn1.TagClass;
import model.asn1.exceptions.ParseException;
import model.asn1.parsing.BytesReader;
import model.pki.SubjectPublicKeyInfo;
import model.x501.Name;

import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Stream;

/**
 * Represents a RFC2986 / PKCS#10 CSR CertificationRequestInfo object.
 * For more info on CRL, see {@link CertificationRequest}.
 *
 * <pre>
 *    DEFINITIONS IMPLICIT TAGS ::=
 *
 *    CertificationRequestInfo ::= SEQUENCE {
 *         version       INTEGER { v1(0) } (v1,...),
 *         subject       Name,
 *         subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
 *         attributes    [0] Attributes{{ CRIAttributes }}
 *    }
 *
 * </pre>
 * <p>
 * It represents all information of a CSR (version, subject, public key, attributes).
 * It will be signed, and the signature is in {@link CertificationRequest}.
 */
public class CertificationRequestInfo extends ASN1Object {
    public static final int VERSION_V1 = 0;

    /**
     * Version of the CRL. Always {@link CertificationRequestInfo#VERSION_V1} (0).
     */
    @Assoc(partOf = true)
    private final Int version;

    /**
     * Subject of the requested certificate
     */
    @Assoc(partOf = true)
    private final Name subject;

    /**
     * The public key to request.
     */
    @Assoc(partOf = true)
    private final SubjectPublicKeyInfo subjectPKInfo;

    /**
     * The request attributes.
     */
    @Assoc(partOf = true)
    private final Attributes attributes;

    /**
     * EFFECTS: Construct with the given version, subject, pubkey, attributes, and the given tags.
     * REQUIRES: Version must be {@link CertificationRequestInfo#VERSION_V1}. The fields must have correct tags as
     * described in class specification.
     */
    public CertificationRequestInfo(Tag tag, Tag parentTag,
                                    final Int version,
                                    final Name subject,
                                    final SubjectPublicKeyInfo subjectPKInfo,
                                    final Attributes attributes) {
        super(tag, parentTag);
        this.version = version;
        this.subject = subject;
        this.subjectPKInfo = subjectPKInfo;
        this.attributes = attributes;
    }

    /**
     * EFFECTS: Parse the object with the given DER input.
     * Throws {@link ParseException} if the input is invalid:
     * - Any fields missing (version, subject, subjectPKInfo, attributes)
     * - 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 CertificationRequestInfo(BytesReader encoded, boolean hasParentTag) throws ParseException {
        super(encoded, hasParentTag);
        this.version = new Int(encoded, false);
        this.version.getTag().enforce(Int.TAG);
        if (this.version.getLong() != VERSION_V1) {
            throw new ParseException("Illegal version " + this.version.getLong());
        }

        this.subject = new Name(encoded, false);
        this.subject.getTag().enforce(TAG_SEQUENCE);

        this.subjectPKInfo = new SubjectPublicKeyInfo(encoded, false);
        this.subjectPKInfo.getTag().enforce(TAG_SEQUENCE);

        this.attributes = new Attributes(encoded, false);
        this.attributes.getTag().enforce(new Tag(TagClass.CONTEXT_SPECIFIC, true, 0));
    }

    /**
     * EFFECTS: Encode the value of that object, in the same order and format as denoted in the ASN.1 specification.
     */
    @Override
    public Byte[] encodeValueDER() {
        return Stream.of(Arrays.asList(version.encodeDER()),
                        Arrays.asList(subject.encodeDER()),
                        Arrays.asList(subjectPKInfo.encodeDER()),
                        Arrays.asList(attributes.encodeDER()))
                .flatMap(Collection::stream)
                .toArray(Byte[]::new);
    }

    public Int getVersion() {
        return version;
    }

    public Name getSubject() {
        return subject;
    }

    public SubjectPublicKeyInfo getSubjectPKInfo() {
        return subjectPKInfo;
    }

    public Attributes getAttributes() {
        return attributes;
    }
}