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 }