1 /**
2 * EAC11 CVC
3 * 
4 * Copyright:
5 * (C) 2008 Falko Strenzke
6 *     2008 Jack Lloyd
7 * (C) 2014-2015 Etienne Cimon
8 *
9 * License:
10 * Botan is released under the Simplified BSD License (see LICENSE.md)
11 */
12 module botan.cert.cvc.cvc_cert;
13 
14 import botan.constants;
15 static if (BOTAN_HAS_CARD_VERIFIABLE_CERTIFICATES):
16 
17 public import botan.cert.cvc.cvc_gen_cert;
18 public import botan.cert.cvc.eac_asn_obj;
19 import botan.filters.pipe;
20 import botan.pubkey.x509_key;
21 import botan.cert.cvc.signed_obj;
22 import botan.asn1.oids;
23 import botan.asn1.asn1_obj;
24 import botan.pubkey.algo.ecdsa;
25 import botan.utils.types;
26 
27 alias EAC11CVC = RefCounted!EAC11CVCImpl;
28 
29 /**
30 * This class represents TR03110 (EAC) v1.1 CV Certificates
31 */
32 final class EAC11CVCImpl : EAC11genCVC!EAC11CVCImpl, SignedObject
33 {
34 public:
35     /**
36     * Get the CAR of the certificate.
37     * Returns: the CAR of the certificate
38     */
39     const(ASN1Car) getCar() const
40     {
41         return m_car;
42     }
43 
44     /**
45     * Get the CED of this certificate.
46     * Returns: the CED this certificate
47     */
48     const(ASN1Ced) getCed() const
49     {
50         return m_ced;
51     }
52 
53     /**
54     * Get the CEX of this certificate.
55     * Returns: the CEX this certificate
56     */
57     const(ASN1Cex) getCex() const
58     {
59         return m_cex;
60     }
61 
62     /**
63     * Get the CHAT value.
64     * Returns: the CHAT value
65     */
66     ubyte getChatValue() const
67     {
68         return m_chat_val;
69     }
70 
71     bool opEquals(in EAC11CVC rhs) const
72     {
73         return (tbsData() == rhs.tbsData()
74                 && getConcatSig() == rhs.getConcatSig());
75     }
76 
77     /*
78     * Comparison
79     */
80     int opCmp(in EAC11CVCImpl rhs) const
81     {
82         if (this == rhs) return 0;
83         else return -1;
84     }
85 
86     /**
87     * Construct a CVC from a data source
88     * Params:
89     *  input = the data source
90     */
91     this(DataSource input)
92     {
93         init(input);
94         m_self_signed = false;
95         doDecode();
96     }
97 
98     /**
99     * Construct a CVC from a file
100     * Params:
101     *  input = the path to the certificate file
102     */
103     this(in string input)
104     {
105         auto stream = DataSourceStream(input, true);
106         init(cast(DataSource)stream);
107         m_self_signed = false;
108         doDecode();
109     }
110 
111     /**
112     * Construct a CVC from the copy of another CVC
113     * Params:
114     *  other = the other CVC
115     */
116     this(const ref EAC11CVC other) {
117         m_sig = other.m_sig.dup;
118         m_sig_algo = AlgorithmIdentifier(other.m_sig_algo);
119         m_tbs_bits = other.m_tbs_bits.dup;
120         m_PEM_labels_allowed = other.m_PEM_labels_allowed.dup;
121         
122         m_pk = cast(ECDSAPublicKey) other.m_pk; // no copy of this...
123         m_chr = ASN1Chr(other.m_chr);
124         m_self_signed = other.m_self_signed;
125 
126         m_car = ASN1Car(other.m_car);
127         m_ced = ASN1Ced(other.m_ced);
128         m_cex = ASN1Cex(other.m_cex);
129         m_chat_val = other.m_chat_val;
130         m_chat_oid = OID(other.m_chat_oid);
131 
132     }
133 
134     /**
135     * Assign references to another CVC object
136     * Params:
137     *  other = the other CVC object
138     */
139     void opAssign(ref EAC11CVC other) {
140         m_sig = other.m_sig;
141         m_sig_algo = other.m_sig_algo;
142         m_tbs_bits = other.m_tbs_bits.dup;
143         m_PEM_labels_allowed = other.m_PEM_labels_allowed;
144         m_pk = other.m_pk;
145         m_chr = other.m_chr;
146         m_self_signed = other.m_self_signed;
147 
148         m_car = other.m_car;
149         m_ced = other.m_ced;
150         m_cex = other.m_cex;
151         m_chat_val = other.m_chat_val;
152         m_chat_oid = other.m_chat_oid;
153     }
154 
155     // Interface fall-through
156     override const(Vector!ubyte) getConcatSig() const { return super.getConcatSig(); }
157     override void encode(Pipe pipe, X509Encoding encoding = PEM_) const { return super.encode(pipe, encoding); }
158     override const(Vector!ubyte) tbsData() const { return super.tbsData(); }
159 
160     ~this() {}
161 protected:
162     /*
163     * Decode the TBSCertificate data
164     */
165     override void forceDecode()
166     {
167         Vector!ubyte enc_pk;
168         Vector!ubyte enc_chat_val;
169         size_t cpi;
170         BERDecoder tbs_cert = BERDecoder(m_tbs_bits);
171         tbs_cert.decode(cpi, (cast(ASN1Tag)41), ASN1Tag.APPLICATION)
172                 .decode(m_car)
173                 .startCons((cast(ASN1Tag)73), ASN1Tag.APPLICATION)
174                 .rawBytes(enc_pk)
175                 .endCons()
176                 .decode(m_chr)
177                 .startCons((cast(ASN1Tag)76), ASN1Tag.APPLICATION)
178                 .decode(m_chat_oid)
179                 .decode(enc_chat_val, ASN1Tag.OCTET_STRING, (cast(ASN1Tag)19), ASN1Tag.APPLICATION)
180                 .endCons()
181                 .decode(m_ced)
182                 .decode(m_cex)
183                 .verifyEnd();
184         
185         if (enc_chat_val.length != 1)
186             throw new DecodingError("CertificateHolderAuthorizationValue was not of length 1");
187         
188         if (cpi != 0)
189             throw new DecodingError("EAC1_1 certificate's cpi was not 0");
190         
191         m_pk = decodeEac11Key(enc_pk, m_sig_algo);
192 
193         m_chat_val = enc_chat_val[0];
194 
195         m_self_signed = (m_car.iso8859() == m_chr.iso8859());
196     }
197 
198     this() {}
199 
200     ASN1Car m_car;
201     ASN1Ced m_ced;
202     ASN1Cex m_cex;
203     ubyte m_chat_val;
204     OID m_chat_oid;
205 }
206 
207 /**
208 * Create an arbitrary EAC 1.1 CVC.
209 * The desired key encoding must be set within the key (if applicable).
210 * Params:
211 *  signer = the signer used to sign the certificate
212 *  public_key = the DER encoded public key to appear in
213 * the certificate
214 *  car = the CAR of the certificate
215 *  chr = the CHR of the certificate
216 *  holder_auth_templ = the holder authorization value ubyte to
217 * appear in the CHAT of the certificate
218 *  ced = the CED to appear in the certificate
219 *  cex = the CEX to appear in the certificate
220 *  rng = a random number generator
221 */
222 EAC11CVC makeCvcCert(ALLOC)(ref PKSigner signer,
223                                 const ref Vector!(ubyte, ALLOC) public_key,
224                                 in ASN1Car car,
225                                 in ASN1Chr chr,
226                                 in ubyte holder_auth_templ,
227                                 in ASN1Ced ced,
228                                 in ASN1Cex cex,
229                                 RandomNumberGenerator rng)
230 {
231     OID chat_oid = OIDS.lookup("CertificateHolderAuthorizationTemplate");
232     Vector!ubyte enc_chat_val;
233     enc_chat_val.pushBack(holder_auth_templ);
234     
235     Vector!ubyte enc_cpi;
236     enc_cpi.pushBack(0x00);
237     Vector!ubyte tbs = DEREncoder()
238                         .encode(enc_cpi, ASN1Tag.OCTET_STRING, (cast(ASN1Tag)41), ASN1Tag.APPLICATION) // cpi
239                         .encode(car)
240                         .rawBytes(public_key)
241                         .encode(chr)
242                         .startCons((cast(ASN1Tag)76), ASN1Tag.APPLICATION)
243                         .encode(chat_oid)
244                         .encode(enc_chat_val, ASN1Tag.OCTET_STRING, (cast(ASN1Tag)19), ASN1Tag.APPLICATION)
245                         .endCons()
246                         .encode(ced)
247                         .encode(cex)
248                         .getContentsUnlocked();
249     
250     Vector!ubyte signed_cert = EAC11CVC.makeSigned(signer, EAC11CVC.buildCertBody(tbs), rng);
251     
252     auto source = DataSourceMemory(&signed_cert);
253     return EAC11CVC(cast(DataSource)source);
254 }
255 
256 /// ditto
257 EAC11CVC makeCvcCert(ALLOC)(ref PKSigner signer,
258                             auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) public_key,
259                             in ASN1Car car,
260                             in ASN1Chr chr,
261                             in ubyte holder_auth_templ,
262                             in ASN1Ced ced,
263                             in ASN1Cex cex,
264                             RandomNumberGenerator rng)
265 {
266     return makeCvcCert(signer, *public_key, car, chr, holder_auth_templ, ced, cex, rng);
267 }
268 /**
269 * Decode an EAC encoding ECDSA key
270 */
271 
272 ECDSAPublicKey decodeEac11Key(const ref Vector!ubyte,
273                               ref AlgorithmIdentifier)
274 {
275     throw new InternalError("decodeEac11Key: Unimplemented");
276 }