1 /**
2 * EAC11 CVC ADO
3 * 
4 * Copyright:
5 * (C) 2008 Falko Strenzke
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.cert.cvc.cvc_ado;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_CARD_VERIFIABLE_CERTIFICATES):
15 
16 import botan.cert.cvc.eac_obj;
17 import botan.cert.cvc.signed_obj;
18 import botan.cert.cvc.eac_asn_obj;
19 import botan.cert.cvc.cvc_req;
20 import botan.cert.cvc.ecdsa_sig;
21 import botan.rng.rng;
22 import botan.pubkey.pubkey;
23 import botan.filters.data_src;
24 import botan.filters.pipe;
25 import botan.pubkey.x509_key;
26 import botan.asn1.asn1_obj;
27 import botan.utils.types;
28 import std.typecons : scoped;
29 
30 alias EAC11ADO = RefCounted!EAC11ADOImpl;
31 /**
32 * This class represents a TR03110 (EAC) v1.1 CVC ADO request
33 */
34 
35  // CRTP continuation from EAC11obj
36 final class EAC11ADOImpl : EAC11obj!EAC11ADOImpl, SignedObject
37 {
38 public:
39     override const(Vector!ubyte) getConcatSig() const { return super.getConcatSig(); }
40     /**
41     * Construct a CVC ADO request from a DER encoded CVC ADO request file.
42     *
43     * Params:
44     *  input = the path to the DER encoded file
45     */
46     this(in string input)
47     {
48         auto stream = DataSourceStream(input, true);
49         init(cast(DataSource)stream);
50         doDecode();
51     }
52 
53     /**
54     * Construct a CVC ADO request from a data source
55     * Params:
56     *  input = the data source
57     */
58     this(DataSource input)
59     {
60         init(input);
61         doDecode();
62     }
63 
64     /**
65     * Create a signed CVC ADO request from to be signed (TBS) data
66     * Params:
67     *  signer = the signer used to sign the CVC ADO request
68     *  tbs_bits = the TBS data to sign
69     *  rng = a random number generator
70     */
71     static Vector!ubyte makeSigned(ALLOC)(ref PKSigner signer,
72                                                 auto const ref Vector!(ubyte, ALLOC) tbs_bits,
73                                                 RandomNumberGenerator rng)
74     {
75         const Vector!ubyte concat_sig = signer.signMessage(tbs_bits, rng);
76         
77         return DEREncoder()
78                 .startCons((cast(ASN1Tag)7), ASN1Tag.APPLICATION)
79                 .rawBytes(tbs_bits)
80                 .encode(concat_sig, ASN1Tag.OCTET_STRING, (cast(ASN1Tag)55), ASN1Tag.APPLICATION)
81                 .endCons()
82                 .getContentsUnlocked();
83     }
84 
85     static Vector!ubyte makeSigned(ALLOC)(ref PKSigner signer,
86                                           auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) tbs_bits,
87                                           RandomNumberGenerator rng)
88     {
89         return makeSigned(signer, **tbs_bits, rng);
90     }
91 
92     /**
93     * Get the CAR of this CVC ADO request
94     * Returns: the CAR of this CVC ADO request
95     */
96     const(ASN1Car) getCar() const
97     {
98         return m_car;
99     }
100 
101     /**
102     * Get the CVC request contained in this object.
103     * Returns: the CVC request inside this CVC ADO request
104     */    
105     const(EAC11Req) getRequest() const
106     {
107         return m_req;
108     }
109 
110     /**
111     * Encode this object into a pipe. Only DER is supported.
112     *
113     * Params:
114     *  output = the pipe to encode this object into
115     *  encoding = the encoding type to use, must be DER
116     */
117     override void encode(Pipe output, X509Encoding encoding) const
118     {
119         if (encoding == PEM_)
120             throw new InvalidArgument("encode() cannot PEM encode an EAC object");
121         
122         auto concat_sig = m_sig.getConcatenation();
123         
124         output.write(DEREncoder()
125                      .startCons((cast(ASN1Tag)7), ASN1Tag.APPLICATION)
126                      .rawBytes(m_tbs_bits)
127                      .encode(concat_sig, ASN1Tag.OCTET_STRING, (cast(ASN1Tag)55), ASN1Tag.APPLICATION)
128                      .endCons()
129                      .getContents());
130     }
131 
132     bool opEquals(in EAC11ADO rhs) const
133     {
134         return (getConcatSig() == rhs.getConcatSig()
135                 && tbsData() == rhs.tbsData()
136                 && getCar() ==  rhs.getCar());
137     }
138 
139     /**
140     * Get the TBS data of this CVC ADO request.
141     * Returns: the TBS data
142     */
143     override const(Vector!ubyte) tbsData() const
144     {
145         return m_tbs_bits.dup;
146     }
147 
148 
149     int opCmp(in EAC11ADOImpl rhs) const
150     {
151         if (this == rhs)
152             return 0;
153         else return -1; // no comparison support
154     }
155 
156     /**
157     * Construct a CVC ADO request from a copy of another ADO object
158     * Params:
159     *  other = the other object
160     */
161     this(ref EAC11ADO other)
162     {
163         m_sig = other.m_sig.dup;
164         m_sig_algo = AlgorithmIdentifier(other.m_sig_algo);
165         m_tbs_bits = other.m_tbs_bits.dup;
166         m_PEM_labels_allowed = other.m_PEM_labels_allowed;
167 
168         m_car = ASN1Car(other.m_car);
169         m_req = EAC11Req(other.m_req);
170     }
171 
172     /**
173     * Replace this ADO request with references to another one
174     * Params:
175     *  other = the other object
176     */
177     void opAssign(ref EAC11ADO other)
178     {
179         m_sig = other.m_sig;
180         m_sig_algo = other.m_sig_algo;
181         m_tbs_bits = other.m_tbs_bits.dup;
182         m_PEM_labels_allowed = other.m_PEM_labels_allowed;
183 
184         m_car = other.m_car;
185         m_req = other.m_req;
186     }
187 
188 protected:
189     ASN1Car m_car;
190     EAC11Req m_req;
191 
192     override void forceDecode()
193     {
194         Vector!ubyte inner_cert;
195         BERDecoder(m_tbs_bits)
196                     .startCons((cast(ASN1Tag)33), ASN1Tag.APPLICATION)
197                     .rawBytes(inner_cert)
198                     .endCons()
199                     .decode(m_car)
200                     .verifyEnd();
201         
202         Vector!ubyte req_bits = DEREncoder()
203                                 .startCons((cast(ASN1Tag)33), ASN1Tag.APPLICATION)
204                                 .rawBytes(inner_cert)
205                                 .endCons()
206                                 .getContentsUnlocked();
207         
208         auto req_source = DataSourceMemory(&req_bits);
209         m_req = EAC11Req(cast(DataSource)req_source);
210         m_sig_algo = cast(AlgorithmIdentifier) m_req.signatureAlgorithm();
211     }
212 
213 
214 package:
215     static void decodeInfo(ALLOC)(DataSource source,
216                                   auto ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) res_tbs_bits,
217                                   ref ECDSASignature res_sig)
218     {
219         return decodeInfo(source, **res_tbs_bits, res_sig);
220     }
221 
222     static void decodeInfo(ALLOC)(DataSource source,
223                                      auto ref Vector!(ubyte, ALLOC) res_tbs_bits,
224                                      ref ECDSASignature res_sig)
225     {
226         Vector!ubyte concat_sig;
227         Vector!ubyte cert_inner_bits;
228         ASN1Car car;
229         
230         BERDecoder(source)
231             .startCons((cast(ASN1Tag)7), ASN1Tag.APPLICATION)
232                 .startCons((cast(ASN1Tag)33), ASN1Tag.APPLICATION)
233                 .rawBytes(cert_inner_bits)
234                 .endCons()
235                 .decode(car)
236                 .decode(concat_sig, ASN1Tag.OCTET_STRING, (cast(ASN1Tag)55), ASN1Tag.APPLICATION)
237                 .endCons();
238         
239         Vector!ubyte enc_cert = DEREncoder()
240                 .startCons((cast(ASN1Tag)33), ASN1Tag.APPLICATION)
241                 .rawBytes(cert_inner_bits)
242                 .endCons()
243                 .getContentsUnlocked();
244         
245         res_tbs_bits = enc_cert.move();
246         res_tbs_bits ~= DEREncoder().encode(car).getContentsUnlocked();
247         res_sig = decodeConcatenation(concat_sig);
248     }
249 }