1 /**
2 * CVC EAC1.1 tests
3 *
4 * Copyright:
5 * (C) 2008 Falko Strenzke (strenzke@flexsecure.de)
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.test;
13 
14 import botan.constants;
15 static if (BOTAN_TEST && BOTAN_HAS_CARD_VERIFIABLE_CERTIFICATES):
16 
17 import botan.test;
18 import botan.rng.auto_rng;
19 import botan.pubkey.algo.ecdsa;
20 import botan.pubkey.algo.rsa;
21 
22 import botan.cert.x509.x509cert;
23 import botan.cert.x509.x509self;
24 import botan.asn1.oids;
25 import botan.cert.cvc.cvc_self;
26 import botan.cert.cvc.cvc_ado;
27 import botan.cert.cvc.cvc_cert;
28 import botan.cert.cvc.signed_obj;
29 import botan.utils.types;
30 import std.datetime;
31 
32 
33 // helper functions
34 void helperWriteFile(in EACSignedObject to_write, in string file_path)
35 {
36     Array!ubyte sv = to_write.BER_encode();
37     File cert_file = File(file_path, "wb+");
38     cert_file.write(sv.ptr[0 .. sv.length]);
39 }
40 
41 
42 bool helperFilesEqual(in string file_path1, in string file_path2)
43 {
44     File cert_1_in = File(file_path1, "r");
45     File cert_2_in = File(file_path2, "r");
46     Vector!ubyte sv1;
47     Vector!ubyte sv2;
48     if (!cert_1_in.ok || !cert_2_in.ok)
49     {
50         return false;
51     }
52     while (!cert_1_in.eof && !cert_1_in.error)
53     {
54         ubyte[16] now;
55         auto data = cert_1_in.rawRead(now.ptr[0 .. now.length]);
56         sv1.pushBack(data);
57     }
58     while (!cert_2_in.eof && !cert_2_in.error)
59     {
60         ubyte[16] now;
61         auto data = cert_2_in.rawRead(now.ptr[0 .. now.length]);
62         sv2.pushBack(data);
63     }
64     if (sv1.length == 0)
65     {
66         return false;
67     }
68     return sv1 == sv2;
69 }
70 
71 void testEncGenSelfsigned(RandomNumberGenerator rng)
72 {
73 
74     size_t fails;
75     size_t total_tests;
76     scope(exit) testReport("testEncGenSelfSigned", total_tests, fails);
77 
78     EAC11CVCOptions opts;
79     //opts.cpi = 0;
80     opts.chr = ASN1Chr("my_opt_chr"); // not used
81     opts.car = ASN1Car("my_opt_car");
82     opts.cex = ASN1Cex("2010 08 13");
83     opts.ced = ASN1Ced("2010 07 27");
84     opts.holder_auth_templ = 0xC1;
85     opts.hash_alg = "SHA-256";
86     
87     // creating a non sense selfsigned cert w/o dom pars
88     ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.11"));
89     auto key = ECDSAPrivateKey(rng, dom_pars);
90     key.setParameterEncoding(EC_DOMPAR_ENC_IMPLICITCA);
91     EAC11CVC cert = createSelfSignedCert(key, opts, rng);
92     {
93         Array!ubyte der = cert.BER_encode();
94         File cert_file = File("../test_data/ecc/my_cv_cert.ber", "wb+");
95         //cert_file << der; // this is bad !!!
96         cert_file.write(cast(string) der.ptr[0 .. der.length]);
97     }
98     
99     EAC11CVC cert_in = EAC11CVC("../test_data/ecc/my_cv_cert.ber");
100     mixin( CHECK(` cert == cert_in `) );
101     // encoding it again while it has no dp
102     {
103         Array!ubyte der2 = cert_in.BER_encode();
104         File cert_file2 = File("../test_data/ecc/my_cv_cert2.ber", "wb+");
105         cert_file2.write(der2.ptr[0 .. der2.length]);
106     }
107     // read both and compare them
108     {
109         File cert_1_in = File("../test_data/ecc/my_cv_cert.ber", "r");
110         File cert_2_in = File("../test_data/ecc/my_cv_cert2.ber", "r");
111         Vector!ubyte sv1;
112         Vector!ubyte sv2;
113         if (!cert_1_in.ok || !cert_2_in.ok)
114         {
115             mixin( CHECK_MESSAGE( `false`, "could not read certificate files" ) );
116         }
117         while (!cert_1_in.eof && !cert_1_in.error)
118         {
119             ubyte[16] now;
120             auto data = cert_1_in.rawRead(now.ptr[0 .. now.length]);
121             sv1.pushBack(data);
122         }
123         while (!cert_2_in.eof && !cert_2_in.error)
124         {
125             ubyte[16] now;
126             auto data = cert_2_in.rawRead(now.ptr[0 .. now.length]);
127             sv2.pushBack(data);
128         }
129         mixin( CHECK(` sv1.length > 10 `) );
130         mixin( CHECK_MESSAGE( `sv1 == sv2`, "reencoded file of cert without domain parameters is different from original" ) );
131     }
132     //cout " ~reading cert again");
133     mixin( CHECK(` cert_in.getCar().value() == "my_opt_car" `) );
134     mixin( CHECK(` cert_in.getChr().value() == "my_opt_car" `) );
135     mixin( CHECK(` cert_in.getCed().toString() == "20100727" `) );
136     mixin( CHECK(` cert_in.getCed().readableString() == "2010/07/27 " `) );
137     
138     bool ill_date_exc = false;
139     try
140     {
141         ASN1Ced("1999 01 01");
142     }
143     catch (Exception)
144     {
145         ill_date_exc = true;
146     }
147     mixin( CHECK(` ill_date_exc `) );
148     
149     bool ill_date_exc2 = false;
150     try
151     {
152         ASN1Ced("2100 01 01");
153     }
154     catch (Exception)
155     {
156         ill_date_exc2 = true;
157     }
158     mixin( CHECK(` ill_date_exc2 `) );
159     //cout " ~readable = '" ~ cert_in.getCed().readableString() " ~'");
160     Unique!PublicKey p_pk = cert_in.subjectPublicKey();
161     ECDSAPublicKey p_ecdsa_pk = cast(ECDSAPublicKey)(*p_pk);
162     
163     // let´s see if encoding is truely implicitca, because this is what the key should have
164     // been set to when decoding (see above)(because it has no domain params):
165     
166     mixin( CHECK(` p_ecdsa_pk.domainFormat() == EC_DOMPAR_ENC_IMPLICITCA `) );
167     bool exc = false;
168     try
169     {
170         logTrace("order = ", p_ecdsa_pk.domain().getOrder().dup.toString());
171     }
172     catch (InvalidState)
173     {
174         exc = true;
175     }
176     mixin( CHECK(` exc `) );
177     // set them and try again
178     //cert_in -> setDomainParameters(dom_pars);
179     Unique!PublicKey p_pk2 = cert_in.subjectPublicKey();
180     ECDSAPublicKey p_ecdsa_pk2 = cast(ECDSAPublicKey)(*p_pk2);
181     //p_ecdsa_pk2 -> setDomainParameters(dom_pars);
182     mixin( CHECK(` p_ecdsa_pk2.domain().getOrder() == dom_pars.getOrder() `) );
183     bool ver_ec = cert_in.checkSignature(*p_pk2);
184     mixin( CHECK_MESSAGE( `ver_ec`, "could not positively verify correct selfsigned cvc certificate" ) );
185 
186 }
187 
188 void testEncGenReq(RandomNumberGenerator rng)
189 {
190 
191     size_t fails;
192     size_t total_tests;
193     scope(exit)testReport("testEncGenReq", total_tests, fails);
194 
195     EAC11CVCOptions opts;
196     
197     //opts.cpi = 0;
198     opts.chr = ASN1Chr("my_opt_chr");
199     opts.hash_alg = "SHA-160";
200     
201     // creating a non sense selfsigned cert w/o dom pars
202     ECGroup dom_pars = ECGroup(OID("1.3.132.0.8"));
203     auto key = ECDSAPrivateKey(rng, dom_pars);
204     key.setParameterEncoding(EC_DOMPAR_ENC_IMPLICITCA);
205     EAC11Req req = createCvcReq(key, opts.chr, opts.hash_alg, rng);
206     {
207         Array!ubyte der = req.BER_encode();
208         File req_file = File("../test_data/ecc/my_cv_req.ber", "wb+");
209         req_file.write(der.ptr[0 .. der.length]);
210     }
211     
212     // read and check signature...
213     EAC11Req req_in = EAC11Req("../test_data/ecc/my_cv_req.ber");
214     //req_in.setDomainParameters(dom_pars);
215     Unique!PublicKey p_pk = req_in.subjectPublicKey();
216     ECDSAPublicKey p_ecdsa_pk = cast(ECDSAPublicKey)(*p_pk);
217     //p_ecdsa_pk.setDomainParameters(dom_pars);
218     mixin( CHECK(` p_ecdsa_pk.domain().getOrder() == dom_pars.getOrder() `) );
219     bool ver_ec = req_in.checkSignature(*p_pk);
220     mixin( CHECK_MESSAGE( `ver_ec`, "could not positively verify correct selfsigned (created by myself) cvc request" ) );
221 }
222 
223 void testCvcReqExt(RandomNumberGenerator)
224 {
225     size_t fails;
226     size_t total_tests;
227     scope(exit)testReport("testCvcReqExt", total_tests, fails);
228     EAC11Req req_in = EAC11Req("../test_data/ecc/DE1_flen_chars_cvcRequest_ECDSA.der");
229     ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve"
230     //req_in.setDomainParameters(dom_pars);
231     Unique!PublicKey p_pk = req_in.subjectPublicKey();
232     ECDSAPublicKey p_ecdsa_pk = cast(ECDSAPublicKey)(*p_pk);
233     //p_ecdsa_pk.setDomainParameters(dom_pars);
234     mixin( CHECK(` p_ecdsa_pk.domain().getOrder() == dom_pars.getOrder() `) );
235     bool ver_ec = req_in.checkSignature(*p_pk);
236     mixin( CHECK_MESSAGE( `ver_ec`, "could not positively verify correct selfsigned (external testdata) cvc request" ) );
237 }
238 
239 void testCvcAdoExt(RandomNumberGenerator)
240 {    size_t fails;
241     size_t total_tests;
242     scope(exit)testReport("testCvcAdoExt", total_tests, fails);
243     EAC11ADO req_in = EAC11ADO("../test_data/ecc/ado.cvcreq");
244     ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve"
245     //cout " ~car = " ~ req_in.getCar().value());
246     //req_in.setDomainParameters(dom_pars);
247 }
248 
249 void testCvcAdoCreation(RandomNumberGenerator rng)
250 {    
251     size_t fails;
252     size_t total_tests;
253     scope(exit)testReport("testCvcAdoCreation", total_tests, fails);
254     EAC11CVCOptions opts;
255     //opts.cpi = 0;
256     opts.chr = ASN1Chr("my_opt_chr");
257     opts.hash_alg = "SHA-256";
258     
259     // creating a non sense selfsigned cert w/o dom pars
260     ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.11"));
261     //cout " ~mod = " ~ hex << dom_pars.getCurve().getP());
262     auto req_key = ECDSAPrivateKey(rng, dom_pars);
263     req_key.setParameterEncoding(EC_DOMPAR_ENC_IMPLICITCA);
264     //EAC11Req req = createCvcReq(req_key, opts);
265     EAC11Req req = createCvcReq(req_key, opts.chr, opts.hash_alg, rng);
266     {
267         Array!ubyte der = req.BER_encode();
268         File req_file = File("../test_data/ecc/my_cv_req.ber", "wb+");
269         req_file.write(der.ptr[0 .. der.length]);
270     }
271     
272     // create an ado with that req
273     auto ado_key = ECDSAPrivateKey(rng, dom_pars);
274     EAC11CVCOptions ado_opts;
275     ado_opts.car = ASN1Car("my_ado_car");
276     ado_opts.hash_alg = "SHA-256"; // must be equal to req´s hash alg, because ado takes his sig_algo from it´s request
277     
278     //EAC11ADO ado = createAdoReq(ado_key, req, ado_opts);
279     EAC11ADO ado = createAdoReq(ado_key, req, ado_opts.car, rng);
280     mixin( CHECK_MESSAGE( `ado.checkSignature(ado_key)`, "failure of ado verification after creation" ) );
281     
282     {
283         File ado_file = File("../test_data/ecc/ado", "wb+");
284         Array!ubyte ado_der = ado.BER_encode();
285         ado_file.write(ado_der.ptr[0 .. ado_der.length]);
286     }
287     // read it again and check the signature
288     EAC11ADO ado2 = EAC11ADO("../test_data/ecc/ado");
289     mixin( CHECK(` ado == ado2 `) );
290     //ECDSAPublicKey p_ado_pk = cast(ECDSAPublicKey)(&ado_key);
291     //bool ver = ado2.checkSignature(*p_ado_pk);
292     bool ver = ado2.checkSignature(ado_key);
293     mixin( CHECK_MESSAGE( `ver`, "failure of ado verification after reloading" ) );
294 }
295 
296 void testCvcAdoComparison(RandomNumberGenerator rng)
297 {
298     size_t fails;
299     size_t total_tests;
300     scope(exit)testReport("testCvcAdoComparison", total_tests, fails);
301     EAC11CVCOptions opts;
302     //opts.cpi = 0;
303     opts.chr = ASN1Chr("my_opt_chr");
304     opts.hash_alg = "SHA-224";
305     
306     // creating a non sense selfsigned cert w/o dom pars
307     ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.11"));
308     auto req_key = ECDSAPrivateKey(rng, dom_pars);
309     req_key.setParameterEncoding(EC_DOMPAR_ENC_IMPLICITCA);
310     //EAC11Req req = createCvcReq(req_key, opts);
311     EAC11Req req = createCvcReq(req_key, opts.chr, opts.hash_alg, rng);
312     
313     // create an ado with that req
314     auto ado_key = ECDSAPrivateKey(rng, dom_pars);
315     EAC11CVCOptions ado_opts;
316     ado_opts.car = ASN1Car("my_ado_car1");
317     ado_opts.hash_alg = "SHA-224"; // must be equal to req's hash alg, because ado takes his sig_algo from it's request
318     //EAC11ADO ado = createAdoReq(ado_key, req, ado_opts);
319     EAC11ADO ado = createAdoReq(ado_key, req, ado_opts.car, rng);
320     mixin( CHECK_MESSAGE( `ado.checkSignature(ado_key)`, "failure of ado verification after creation" ) );
321     // make a second one for comparison
322     EAC11CVCOptions opts2;
323     //opts2.cpi = 0;
324     opts2.chr = ASN1Chr("my_opt_chr");
325     opts2.hash_alg = "SHA-160"; // this is the only difference
326     auto req_key2 = ECDSAPrivateKey(rng, dom_pars);
327     req_key.setParameterEncoding(EC_DOMPAR_ENC_IMPLICITCA);
328     //EAC11Req req2 = createCvcReq(req_key2, opts2, rng);
329     EAC11Req req2 = createCvcReq(req_key2, opts2.chr, opts2.hash_alg, rng);
330     auto ado_key2 = ECDSAPrivateKey(rng, dom_pars);
331     EAC11CVCOptions ado_opts2;
332     ado_opts2.car = ASN1Car("my_ado_car1");
333     ado_opts2.hash_alg = "SHA-160"; // must be equal to req's hash alg, because ado takes his sig_algo from it's request
334     
335     EAC11ADO ado2 = createAdoReq(ado_key2, req2, ado_opts2.car, rng);
336     mixin( CHECK_MESSAGE( `ado2.checkSignature(ado_key2)`, "failure of ado verification after creation" ) );
337     
338     mixin( CHECK_MESSAGE( `ado != ado2`, "ado s found to be equal where they are not" ) );
339     //      std::ofstream ado_file("../test_data/ecc/ado");
340     //      Vector!ubyte ado_der(ado.BER_encode());
341     //      ado_file.write((char*)ado_der.ptr, ado_der.length);
342     //      ado_file.close();
343     // read it again and check the signature
344     
345     //     EAC11ADO ado2("../test_data/ecc/ado");
346     //     ECDSAPublicKey p_ado_pk = cast(ECDSAPublicKey)(&ado_key);
347     //     //bool ver = ado2.checkSignature(p_ado_pk);
348     //     bool ver = ado2.checkSignature(ado_key);
349     //     mixin( CHECK_MESSAGE( ver, "failure of ado verification after reloading" ) );
350 }
351 
352 void testEacTime(RandomNumberGenerator)
353 {
354     size_t fails;
355     size_t total_tests;
356     scope(exit)testReport("testEacTime", total_tests, fails);
357     EACTime time = EACTime(Clock.currTime(UTC()));
358     //      logTrace("time as string = " ~ time.toString());
359     EACTime sooner = EACTime("", (cast(ASN1Tag)99));
360     //X509Time sooner("", (cast(ASN1Tag)99));
361     sooner.setTo("2007 12 12");
362     //      logTrace("sooner as string = " ~ sooner.toString());
363     EACTime later = EACTime("2007 12 13");
364     //X509Time later("2007 12 13");
365     //      logTrace("later as string = " ~ later.toString());
366     mixin( CHECK(` sooner <= later `) );
367     mixin( CHECK(` sooner == sooner `) );
368     
369     ASN1Cex my_cex = ASN1Cex("2007 08 01");
370     my_cex.addMonths(12);
371     mixin( CHECK(` my_cex.getYear() == 2008 `) );
372     mixin( CHECK_MESSAGE( ` my_cex.getMonth() == 8 `, "shoult be 8, was `, my_cex.getMonth(), `" ) );
373     
374     my_cex.addMonths(4);
375     mixin( CHECK(` my_cex.getYear() == 2008 `) );
376     mixin( CHECK(` my_cex.getMonth() == 12 `) );
377     
378     my_cex.addMonths(4);
379     mixin( CHECK(` my_cex.getYear() == 2009 `) );
380     mixin( CHECK(` my_cex.getMonth() == 4 `) );
381     
382     my_cex.addMonths(41);
383     mixin( CHECK(` my_cex.getYear() == 2012 `) );
384     mixin( CHECK(` my_cex.getMonth() == 9 `) );
385     
386     
387     
388 }
389 
390 void testVerCvca(RandomNumberGenerator)
391 {
392     size_t fails;
393     size_t total_tests;
394     scope(exit)testReport("testVerCvca", total_tests, fails);
395     EAC11CVC req_in = EAC11CVC("../test_data/ecc/cvca01.cv.crt");
396     
397     bool exc = false;
398     
399     Unique!PublicKey p_pk2 = req_in.subjectPublicKey();
400     ECDSAPublicKey p_ecdsa_pk2 = cast(ECDSAPublicKey)(*p_pk2);
401     bool ver_ec = req_in.checkSignature(*p_pk2);
402     mixin( CHECK_MESSAGE( `ver_ec`, "could not positively verify correct selfsigned cvca certificate" ) );
403     
404     try
405     {
406         p_ecdsa_pk2.domain().getOrder();
407     }
408     catch (InvalidState)
409     {
410         exc = true;
411     }
412     mixin( CHECK(` !exc `) );
413 }
414 
415 void testCopyAndAssignment(RandomNumberGenerator)
416 {
417     size_t fails;
418     size_t total_tests;
419     scope(exit)testReport("testCopyAndAssignment", total_tests, fails);
420     EAC11CVC cert_in = EAC11CVC("../test_data/ecc/cvca01.cv.crt");
421     EAC11CVC cert_cp = EAC11CVC(cert_in);
422     EAC11CVC cert_ass = cert_in;
423     mixin( CHECK(` cert_in == cert_cp `) );
424     mixin( CHECK(` cert_in == cert_ass `) );
425     
426     EAC11ADO ado_in = EAC11ADO("../test_data/ecc/ado.cvcreq");
427     //ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve"
428     EAC11ADO ado_cp = EAC11ADO(ado_in);
429     EAC11ADO ado_ass = ado_in;
430     mixin( CHECK(` ado_in == ado_cp `) );
431     mixin( CHECK(` ado_in == ado_ass `) );
432     
433     EAC11Req req_in = EAC11Req("../test_data/ecc/DE1_flen_chars_cvcRequest_ECDSA.der");
434     //ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve"
435     EAC11Req req_cp = EAC11Req(req_in);
436     EAC11Req req_ass = req_in;
437     mixin( CHECK(` req_in == req_cp `) );
438     mixin( CHECK(` req_in == req_ass `) );
439 }
440 
441 void testEacStrIllegalValues(RandomNumberGenerator)
442 {
443     size_t fails;
444     size_t total_tests;
445     scope(exit)testReport("testCopyAndAssignment", total_tests, fails);
446     bool exc = false;
447     try
448     {
449         EAC11CVC("../test_data/ecc/cvca_illegal_chars.cv.crt");
450         
451     }
452     catch (DecodingError)
453     {
454         exc = true;
455     }
456     mixin( CHECK(` exc `) );
457     
458     bool exc2 = false;
459     try
460     {
461         EAC11CVC("../test_data/ecc/cvca_illegal_chars2.cv.crt");
462         
463     }
464     catch (DecodingError)
465     {
466         exc2 = true;
467     }
468     mixin( CHECK(` exc2 `) );
469 }
470 
471 void testTmpEacStrEnc(RandomNumberGenerator)
472 {
473     size_t fails;
474     size_t total_tests;
475     scope(exit)testReport("testTmpEacStrEnc", total_tests, fails);
476     bool exc = false;
477     try
478     {
479         ASN1Car("abc!+-µ\n");
480     }
481     catch (InvalidArgument)
482     {
483         exc = true;
484     }
485     mixin( CHECK(` exc `) );
486     //      string val = car.iso8859();
487     //      logTrace("car 8859 = " ~ val);
488     //      logTrace(hex <<(unsigned char)val[1]);
489 }
490 
491 void testCvcChain(RandomNumberGenerator rng)
492 {
493     size_t fails;
494     size_t total_tests;
495     scope(exit)testReport("testCvcChain", total_tests, fails);
496     ECGroup dom_pars = ECGroup(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve"
497     auto cvca_privk = ECDSAPrivateKey(rng, dom_pars);
498     string hash = "SHA-224";
499     ASN1Car car = ASN1Car("DECVCA00001");
500     EAC11CVC cvca_cert = cvc_self.createCvca(cvca_privk, hash, car, true, true, 12, rng);
501     {
502         File cvca_file = File("../test_data/ecc/cvc_chain_cvca.cer","wb+");
503         Array!ubyte cvca_sv = cvca_cert.BER_encode();
504         cvca_file.write(cast(string) cvca_sv.ptr[0 .. cvca_sv.length]);
505     }
506     
507     auto cvca_privk2 = ECDSAPrivateKey(rng, dom_pars);
508     ASN1Car car2 = ASN1Car("DECVCA00002");
509     EAC11CVC cvca_cert2 = cvc_self.createCvca(cvca_privk2, hash, car2, true, true, 12, rng);
510     EAC11CVC link12 = cvc_self.linkCvca(cvca_cert, cvca_privk, cvca_cert2, rng);
511     {
512         Array!ubyte link12_sv = link12.BER_encode();
513         File link12_file = File("../test_data/ecc/cvc_chain_link12.cer", "wb+");
514         link12_file.write(link12_sv.ptr[0 .. link12_sv.length]);
515     }
516     
517     // verify the link
518     mixin( CHECK(` link12.checkSignature(cvca_privk) `) );
519     EAC11CVC link12_reloaded = EAC11CVC("../test_data/ecc/cvc_chain_link12.cer");
520     EAC11CVC cvca1_reloaded = EAC11CVC("../test_data/ecc/cvc_chain_cvca.cer");
521     Unique!PublicKey cvca1_rel_pk = cvca1_reloaded.subjectPublicKey();
522     mixin( CHECK(` link12_reloaded.checkSignature(*cvca1_rel_pk) `) );
523     
524     // create first round dvca-req
525     auto dvca_priv_key = ECDSAPrivateKey(rng, dom_pars);
526     EAC11Req dvca_req = cvc_self.createCvcReq(dvca_priv_key, ASN1Chr("DEDVCAEPASS"), hash, rng);
527     {
528         File dvca_file = File("../test_data/ecc/cvc_chain_dvca_req.cer", "wb+");
529         Array!ubyte dvca_sv = dvca_req.BER_encode();
530         dvca_file.write(dvca_sv.ptr[0 .. dvca_sv.length]);
531     }
532     
533     // sign the dvca_request
534     EAC11CVC dvca_cert1 = cvc_self.signRequest(cvca_cert, cvca_privk, dvca_req, 1, 5, true, 3, 1, rng);
535     mixin( CHECK(` dvca_cert1.getCar().iso8859() == "DECVCA00001" `) );
536     mixin( CHECK(` dvca_cert1.getChr().iso8859() == "DEDVCAEPASS00001" `) );
537     helperWriteFile(dvca_cert1, "../test_data/ecc/cvc_chain_dvca_cert1.cer");
538     
539     // make a second round dvca ado request
540     auto dvca_priv_key2 = ECDSAPrivateKey(rng, dom_pars);
541     EAC11Req dvca_req2 = cvc_self.createCvcReq(dvca_priv_key2, ASN1Chr("DEDVCAEPASS"), hash, rng);
542     {
543         File dvca_file2 = File("../test_data/ecc/cvc_chain_dvca_req2.cer", "wb+");
544         Array!ubyte dvca_sv2 = dvca_req2.BER_encode();
545         dvca_file2.write(dvca_sv2.ptr[0 .. dvca_sv2.length]);
546     }
547     
548     EAC11ADO dvca_ado2 = createAdoReq(dvca_priv_key, dvca_req2, ASN1Car(dvca_cert1.getChr().iso8859()), rng);
549     helperWriteFile(dvca_ado2, "../test_data/ecc/cvc_chain_dvca_ado2.cer");
550     
551     // verify the ado and sign the request too
552     
553     Unique!PublicKey ap_pk = dvca_cert1.subjectPublicKey();
554     ECDSAPublicKey cert_pk = cast(ECDSAPublicKey)(*ap_pk);
555     
556     //cert_pk.setDomainParameters(dom_pars);
557     //logTrace("dvca_cert.public_point.length = " ~ ec::EC2OSP(cert_pk.get_publicPoint(), ec::PointGFp.COMPRESSED).length);
558     EAC11CVC dvca_cert1_reread = EAC11CVC("../test_data/ecc/cvc_chain_cvca.cer");
559     mixin( CHECK(` dvca_ado2.checkSignature(cert_pk) `) );
560     
561     mixin( CHECK(` dvca_ado2.checkSignature(dvca_priv_key) `) ); // must also work
562     
563     EAC11Req dvca_req2b = EAC11Req(dvca_ado2.getRequest());
564     helperWriteFile(dvca_req2b, "../test_data/ecc/cvc_chain_dvca_req2b.cer");
565     mixin( CHECK(` helperFilesEqual("../test_data/ecc/cvc_chain_dvca_req2b.cer", "../test_data/ecc/cvc_chain_dvca_req2.cer") `) );
566     EAC11CVC dvca_cert2 = cvc_self.signRequest(cvca_cert, cvca_privk, dvca_req2b, 2, 5, true, 3, 1, rng);
567     mixin( CHECK(` dvca_cert2.getCar().iso8859() == "DECVCA00001" `) );
568     CHECK_MESSAGE(`dvca_cert2.getChr().iso8859() == "DEDVCAEPASS00002"`, "chr = ` ~ dvca_cert2.getChr().iso8859() ~ `");
569     
570     // make a first round IS request
571     auto is_priv_key = ECDSAPrivateKey(rng, dom_pars);
572     EAC11Req is_req = cvc_self.createCvcReq(is_priv_key, ASN1Chr("DEIS"), hash, rng);
573     helperWriteFile(is_req, "../test_data/ecc/cvc_chain_is_req.cer");
574     
575     // sign the IS request
576     //dvca_cert1.setDomainParameters(dom_pars);
577     EAC11CVC is_cert1 = cvc_self.signRequest(dvca_cert1, dvca_priv_key, is_req, 1, 5, true, 3, 1, rng);
578     mixin( CHECK_MESSAGE( `is_cert1.getCar().iso8859() == "DEDVCAEPASS00001"`, "car = ` ~ is_cert1.getCar().iso8859() ~ `" ) );
579     mixin( CHECK(` is_cert1.getChr().iso8859() == "DEIS00001" `) );
580     helperWriteFile(is_cert1, "../test_data/ecc/cvc_chain_is_cert.cer");
581     
582     // verify the signature of the certificate
583     mixin( CHECK(` is_cert1.checkSignature(dvca_priv_key) `) );
584 }
585 
586 static if (BOTAN_HAS_TESTS && !SKIP_CVC_TEST) unittest
587 {
588 
589     logDebug("Testing cvc/test.d ...");
590 	Unique!AutoSeededRNG rng = new AutoSeededRNG;
591     
592     logTrace("testEncGenSelfsigned");
593     testEncGenSelfsigned(*rng);
594     logTrace("testEncGenReq");
595     testEncGenReq(*rng);
596     logTrace("testCvcReqExt");
597     testCvcReqExt(*rng);
598     logTrace("testCvcAdoExt");
599     testCvcAdoExt(*rng);
600     logTrace("testCvcAdoCreation");
601     testCvcAdoCreation(*rng);
602     logTrace("testCvcAdoComparison");
603     testCvcAdoComparison(*rng);
604     logTrace("testEacTime");
605     testEacTime(*rng);
606     logTrace("testVerCvca");
607     testVerCvca(*rng);
608     logTrace("testCopyAndAssignment");
609     testCopyAndAssignment(*rng);
610     logTrace("testEacStrIllegalValues");
611     testEacStrIllegalValues(*rng);
612     logTrace("testTmpEacStrEnc");
613     testTmpEacStrEnc(*rng);
614     logTrace("testCvcChain");
615     testCvcChain(*rng);
616 }