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
|
package model.pki.cert;
import model.asn1.*;
import model.asn1.exceptions.ParseException;
import model.asn1.parsing.BytesReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Stream;
/**
* A X.509v3 certificate extension entry.
* <pre>
* Extension ::= SEQUENCE {
* extnId EXTENSION.&id({ExtensionSet}),
* critical BOOLEAN DEFAULT FALSE,
* extnValue OCTET STRING
* (CONTAINING EXTENSION.&ExtnType({ExtensionSet}{@extnId})
* ENCODED BY der),
* ... }
* </pre>
* Extensions only exist in v3 certificates. They allow the CA and the relying party to add additional verification
* stages to the certificate to constraint its use or to supply additional information. For example, the CA may put a
* CDP (CRL Distribution Point) into the extensions.
*/
public class Extension extends ASN1Object {
/**
* The ID of the type of that extension.
*/
private final ObjectIdentifier extnId;
/**
* Marking an extension critical means that the relying-party
* must reject that certificate if the type is unrecognized.
* If the type is recognized but cannot be fully parsed, the
* behaviour is undefined.
* Marking an extension critical reduces compatibility.
*/
private final Bool critical;
/**
* The DER-encoded ASN.1 content of that extension.
*/
private final OctetString extnValue;
/**
* EFFECTS: Init with tags, extnId, critical, and extnValue. For tags, see {@link ASN1Object}.
* extnValue is not checked against extnId.
* REQUIRES: Tags of extnId, critical, extnValue should be OID, BOOLEAN, OCTET STRING. The value should be a DER
* bytes octet string. If critical is unspecified (which defaults to false), put null.
*/
public Extension(Tag tag, Tag parentTag,
final ObjectIdentifier extnId,
final Bool critical,
final OctetString extnValue) {
super(tag, parentTag);
this.extnId = extnId;
this.critical = critical;
this.extnValue = extnValue;
}
/**
* EFFECTS: Parse input DER.
* 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})
* Note that critical is optional, and if it does not exist, it will be left as null, and it should be treated as
* false.
* MODIFIES: this, encoded
*/
public Extension(BytesReader encoded, boolean hasParentType) throws ParseException {
super(encoded, hasParentType);
this.extnId = new ObjectIdentifier(encoded, false);
this.extnId.getTag().enforce(ObjectIdentifier.TAG);
if (encoded.detectTag(Bool.TAG)) {
critical = new Bool(encoded, false);
} else {
critical = null;
}
this.extnValue = new OctetString(encoded, false);
this.extnValue.getTag().enforce(OctetString.TAG);
}
/**
* EFFECTS: Encode the DER.
*/
@Override
public Byte[] encodeValueDER() {
return Stream.of(Arrays.asList(extnId.encodeDER()),
critical == null ? Collections.<Byte>emptyList() :
Arrays.asList(critical.encodeDER()),
Arrays.asList(extnValue.encodeDER()))
.flatMap(Collection::stream)
.toArray(Byte[]::new);
}
public ObjectIdentifier getExtnId() {
return extnId;
}
public Bool getCritical() {
return critical;
}
public OctetString getExtnValue() {
return extnValue;
}
}
|