1 /*
2 (C) 2007 FlexSecure GmbH
3 2008-2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7
8 #include <botan/cvc_self.h>
9 #include <botan/ecc_key.h>
10 #include <botan/point_gfp.h>
11 #include <botan/time.h>
12 #include <botan/oids.h>
13 #include <sstream>
14 #include <memory>
15
16 namespace Botan {
17
18 namespace {
19
20 /*
21 * cvc CHAT values
22 */
23 enum CHAT_values{
24 CVCA = 0xC0,
25 DVCA_domestic = 0x80,
26 DVCA_foreign = 0x40,
27 IS = 0x00,
28
29 IRIS = 0x02,
30 FINGERPRINT = 0x01
31 };
32
encode_eac_bigint(DER_Encoder & der,const BigInt & x,ASN1_Tag tag)33 void encode_eac_bigint(DER_Encoder& der, const BigInt& x, ASN1_Tag tag)
34 {
35 der.encode(BigInt::encode_1363(x, x.bytes()), OCTET_STRING, tag);
36 }
37
eac_1_1_encoding(const EC_PublicKey * key,const OID & sig_algo)38 MemoryVector<byte> eac_1_1_encoding(const EC_PublicKey* key,
39 const OID& sig_algo)
40 {
41 if(key->domain_format() == EC_DOMPAR_ENC_OID)
42 throw Encoding_Error("CVC encoder: cannot encode parameters by OID");
43
44 const EC_Group& domain = key->domain();
45
46 // This is why we can't have nice things
47
48 DER_Encoder enc;
49 enc.start_cons(ASN1_Tag(73), APPLICATION)
50 .encode(sig_algo);
51
52 if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT)
53 {
54 encode_eac_bigint(enc, domain.get_curve().get_p(), ASN1_Tag(1));
55 encode_eac_bigint(enc, domain.get_curve().get_a(), ASN1_Tag(2));
56 encode_eac_bigint(enc, domain.get_curve().get_b(), ASN1_Tag(3));
57
58 enc.encode(EC2OSP(domain.get_base_point(), PointGFp::UNCOMPRESSED),
59 OCTET_STRING, ASN1_Tag(4));
60
61 encode_eac_bigint(enc, domain.get_order(), ASN1_Tag(4));
62 }
63
64 enc.encode(EC2OSP(key->public_point(), PointGFp::UNCOMPRESSED),
65 OCTET_STRING, ASN1_Tag(6));
66
67 if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT)
68 encode_eac_bigint(enc, domain.get_cofactor(), ASN1_Tag(7));
69
70 enc.end_cons();
71
72 return enc.get_contents();
73 }
74
padding_and_hash_from_oid(OID const & oid)75 std::string padding_and_hash_from_oid(OID const& oid)
76 {
77 std::string padding_and_hash = OIDS::lookup(oid); // use the hash
78
79 if(padding_and_hash.substr(0,6) != "ECDSA/")
80 throw Invalid_State("CVC: Can only use ECDSA, not " + padding_and_hash);
81
82 padding_and_hash.erase(0, padding_and_hash.find("/") + 1);
83 return padding_and_hash;
84 }
85
86 }
87
88 namespace CVC_EAC {
89
create_self_signed_cert(Private_Key const & key,EAC1_1_CVC_Options const & opt,RandomNumberGenerator & rng)90 EAC1_1_CVC create_self_signed_cert(Private_Key const& key,
91 EAC1_1_CVC_Options const& opt,
92 RandomNumberGenerator& rng)
93 {
94 // NOTE: we ignore the value of opt.chr
95
96 const ECDSA_PrivateKey* priv_key = dynamic_cast<const ECDSA_PrivateKey*>(&key);
97
98 if(priv_key == 0)
99 throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
100
101 ASN1_Chr chr(opt.car.value());
102
103 AlgorithmIdentifier sig_algo;
104 std::string padding_and_hash("EMSA1_BSI(" + opt.hash_alg + ")");
105 sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash);
106 sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM);
107
108 PK_Signer signer(*priv_key, padding_and_hash);
109
110 MemoryVector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
111
112 return make_cvc_cert(signer,
113 enc_public_key,
114 opt.car, chr,
115 opt.holder_auth_templ,
116 opt.ced, opt.cex, rng);
117 }
118
create_cvc_req(Private_Key const & key,ASN1_Chr const & chr,std::string const & hash_alg,RandomNumberGenerator & rng)119 EAC1_1_Req create_cvc_req(Private_Key const& key,
120 ASN1_Chr const& chr,
121 std::string const& hash_alg,
122 RandomNumberGenerator& rng)
123 {
124
125 ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
126 if (priv_key == 0)
127 {
128 throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
129 }
130 AlgorithmIdentifier sig_algo;
131 std::string padding_and_hash("EMSA1_BSI(" + hash_alg + ")");
132 sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash);
133 sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM);
134
135 PK_Signer signer(*priv_key, padding_and_hash);
136
137 MemoryVector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
138
139 MemoryVector<byte> enc_cpi;
140 enc_cpi.push_back(0x00);
141 MemoryVector<byte> tbs = DER_Encoder()
142 .encode(enc_cpi, OCTET_STRING, ASN1_Tag(41), APPLICATION)
143 .raw_bytes(enc_public_key)
144 .encode(chr)
145 .get_contents();
146
147 MemoryVector<byte> signed_cert =
148 EAC1_1_gen_CVC<EAC1_1_Req>::make_signed(signer,
149 EAC1_1_gen_CVC<EAC1_1_Req>::build_cert_body(tbs),
150 rng);
151
152 DataSource_Memory source(signed_cert);
153 return EAC1_1_Req(source);
154 }
155
create_ado_req(Private_Key const & key,EAC1_1_Req const & req,ASN1_Car const & car,RandomNumberGenerator & rng)156 EAC1_1_ADO create_ado_req(Private_Key const& key,
157 EAC1_1_Req const& req,
158 ASN1_Car const& car,
159 RandomNumberGenerator& rng)
160 {
161
162 ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
163 if (priv_key == 0)
164 {
165 throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
166 }
167 std::string padding_and_hash = padding_and_hash_from_oid(req.signature_algorithm().oid);
168 PK_Signer signer(*priv_key, padding_and_hash);
169 SecureVector<byte> tbs_bits = req.BER_encode();
170 tbs_bits += DER_Encoder().encode(car).get_contents();
171
172 MemoryVector<byte> signed_cert =
173 EAC1_1_ADO::make_signed(signer, tbs_bits, rng);
174
175 DataSource_Memory source(signed_cert);
176 return EAC1_1_ADO(source);
177 }
178
179 } // namespace CVC_EAC
180 namespace DE_EAC
181 {
182
create_cvca(Private_Key const & key,std::string const & hash,ASN1_Car const & car,bool iris,bool fingerpr,u32bit cvca_validity_months,RandomNumberGenerator & rng)183 EAC1_1_CVC create_cvca(Private_Key const& key,
184 std::string const& hash,
185 ASN1_Car const& car, bool iris, bool fingerpr,
186 u32bit cvca_validity_months,
187 RandomNumberGenerator& rng)
188 {
189 ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
190 if (priv_key == 0)
191 {
192 throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
193 }
194 EAC1_1_CVC_Options opts;
195 opts.car = car;
196 const u64bit current_time = system_time();
197
198 opts.ced = ASN1_Ced(current_time);
199 opts.cex = ASN1_Cex(opts.ced);
200 opts.cex.add_months(cvca_validity_months);
201 opts.holder_auth_templ = (CVCA | (iris * IRIS) | (fingerpr * FINGERPRINT));
202 opts.hash_alg = hash;
203 return CVC_EAC::create_self_signed_cert(*priv_key, opts, rng);
204 }
205
206
207
link_cvca(EAC1_1_CVC const & signer,Private_Key const & key,EAC1_1_CVC const & signee,RandomNumberGenerator & rng)208 EAC1_1_CVC link_cvca(EAC1_1_CVC const& signer,
209 Private_Key const& key,
210 EAC1_1_CVC const& signee,
211 RandomNumberGenerator& rng)
212 {
213 ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
214 if (priv_key == 0)
215 {
216 throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
217 }
218 ASN1_Ced ced(system_time());
219 ASN1_Cex cex(signee.get_cex());
220 if (*static_cast<EAC_Time*>(&ced) > *static_cast<EAC_Time*>(&cex))
221 {
222 std::string detail("link_cvca(): validity periods of provided certificates don't overlap: currend time = ced = ");
223 detail += ced.as_string();
224 detail += ", signee.cex = ";
225 detail += cex.as_string();
226 throw Invalid_Argument(detail);
227 }
228 if (signer.signature_algorithm() != signee.signature_algorithm())
229 {
230 throw Invalid_Argument("link_cvca(): signature algorithms of signer and signee don't match");
231 }
232 AlgorithmIdentifier sig_algo = signer.signature_algorithm();
233 std::string padding_and_hash = padding_and_hash_from_oid(sig_algo.oid);
234 PK_Signer pk_signer(*priv_key, padding_and_hash);
235 std::auto_ptr<Public_Key> pk(signee.subject_public_key());
236 ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
237 subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_EXPLICIT);
238
239 MemoryVector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
240
241 return make_cvc_cert(pk_signer, enc_public_key,
242 signer.get_car(),
243 signee.get_chr(),
244 signer.get_chat_value(),
245 ced, cex,
246 rng);
247 }
248
sign_request(EAC1_1_CVC const & signer_cert,Private_Key const & key,EAC1_1_Req const & signee,u32bit seqnr,u32bit seqnr_len,bool domestic,u32bit dvca_validity_months,u32bit ca_is_validity_months,RandomNumberGenerator & rng)249 EAC1_1_CVC sign_request(EAC1_1_CVC const& signer_cert,
250 Private_Key const& key,
251 EAC1_1_Req const& signee,
252 u32bit seqnr,
253 u32bit seqnr_len,
254 bool domestic,
255 u32bit dvca_validity_months,
256 u32bit ca_is_validity_months,
257 RandomNumberGenerator& rng)
258 {
259 ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
260 if (priv_key == 0)
261 {
262 throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
263 }
264 std::string chr_str = signee.get_chr().value();
265 chr_str += to_string(seqnr, seqnr_len);
266 ASN1_Chr chr(chr_str);
267 std::string padding_and_hash = padding_and_hash_from_oid(signee.signature_algorithm().oid);
268 PK_Signer pk_signer(*priv_key, padding_and_hash);
269 std::auto_ptr<Public_Key> pk(signee.subject_public_key());
270 ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
271 std::auto_ptr<Public_Key> signer_pk(signer_cert.subject_public_key());
272
273 // for the case that the domain parameters are not set...
274 // (we use those from the signer because they must fit)
275 //subj_pk->set_domain_parameters(priv_key->domain_parameters());
276
277 subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
278
279 AlgorithmIdentifier sig_algo(signer_cert.signature_algorithm());
280 const u64bit current_time = system_time();
281 ASN1_Ced ced(current_time);
282 u32bit chat_val;
283 u32bit chat_low = signer_cert.get_chat_value() & 0x3; // take the chat rights from signer
284 ASN1_Cex cex(ced);
285 if ((signer_cert.get_chat_value() & CVCA) == CVCA)
286 {
287 // we sign a dvca
288 cex.add_months(dvca_validity_months);
289 if (domestic)
290 chat_val = DVCA_domestic | chat_low;
291 else
292 chat_val = DVCA_foreign | chat_low;
293 }
294 else if ((signer_cert.get_chat_value() & DVCA_domestic) == DVCA_domestic ||
295 (signer_cert.get_chat_value() & DVCA_foreign) == DVCA_foreign)
296 {
297 cex.add_months(ca_is_validity_months);
298 chat_val = IS | chat_low;
299 }
300 else
301 {
302 throw Invalid_Argument("sign_request(): encountered illegal value for CHAT");
303 // (IS cannot sign certificates)
304 }
305
306 MemoryVector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
307
308 return make_cvc_cert(pk_signer, enc_public_key,
309 ASN1_Car(signer_cert.get_chr().iso_8859()),
310 chr,
311 chat_val,
312 ced,
313 cex,
314 rng);
315 }
316
create_cvc_req(Private_Key const & prkey,ASN1_Chr const & chr,std::string const & hash_alg,RandomNumberGenerator & rng)317 EAC1_1_Req create_cvc_req(Private_Key const& prkey,
318 ASN1_Chr const& chr,
319 std::string const& hash_alg,
320 RandomNumberGenerator& rng)
321 {
322 ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&prkey);
323 if (priv_key == 0)
324 {
325 throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
326 }
327 ECDSA_PrivateKey key(*priv_key);
328 key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
329 return CVC_EAC::create_cvc_req(key, chr, hash_alg, rng);
330 }
331
332 } // namespace DE_EAC
333
334 }
335