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