1 /** 2 * PKCS #10 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 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.x509.pkcs10; 12 13 import botan.constants; 14 static if (BOTAN_HAS_X509_CERTIFICATES): 15 16 import botan.cert.x509.x509_obj; 17 import botan.asn1.x509_dn; 18 import botan.pubkey.pkcs8; 19 import botan.utils.datastor.datastor; 20 import botan.cert.x509.key_constraint; 21 import botan.asn1.asn1_attribute; 22 import botan.asn1.asn1_alt_name; 23 import botan.cert.x509.pkcs10; 24 import botan.cert.x509.x509_ext; 25 import botan.cert.x509.x509cert; 26 import botan.asn1.der_enc; 27 import botan.asn1.ber_dec; 28 import botan.utils.parsing; 29 import botan.asn1.oids; 30 import botan.codec.pem; 31 import botan.utils.types; 32 import botan.utils.exceptn; 33 import botan.utils.mem_ops; 34 import memutils.utils; 35 36 alias PKCS10Request = RefCounted!PKCS10RequestImpl; 37 38 /** 39 * PKCS #10 Certificate Request. 40 */ 41 final class PKCS10RequestImpl : X509Object 42 { 43 public: 44 /** 45 * Get the subject public key. 46 * Returns: subject public key 47 */ 48 PublicKey subjectPublicKey() const 49 { 50 auto source = DataSourceMemory(m_info.get1("X509.Certificate.public_key")); 51 return x509_key.loadKey(cast(DataSource)source); 52 } 53 54 55 /** 56 * Get the raw DER encoded public key. 57 * Returns: the public key of the requestor 58 */ 59 Vector!ubyte rawPublicKey() const 60 { 61 auto source = DataSourceMemory(m_info.get1("X509.Certificate.public_key")); 62 return unlock(PEM.decodeCheckLabel(cast(DataSource)source, "PUBLIC KEY")); 63 } 64 65 /** 66 * Get the subject DN. 67 * Returns: the name of the requestor 68 */ 69 X509DN subjectDn() const 70 { 71 return createDn(m_info); 72 } 73 74 /** 75 * Get the subject alternative name. 76 * Returns: the alternative names of the requestor 77 */ 78 AlternativeName subjectAltName() const 79 { 80 return createAltName(m_info); 81 } 82 83 /** 84 * Get the key constraints for the key associated with this 85 * PKCS#10 object. 86 * Returns: the key constraints (if any) 87 */ 88 KeyConstraints constraints() const 89 { 90 return cast(KeyConstraints)m_info.get1Uint("X509v3.KeyUsage", KeyConstraints.NO_CONSTRAINTS); 91 } 92 93 /** 94 * Get the extendend key constraints (if any). 95 * Returns: the extendend key constraints (if any) 96 */ 97 Vector!OID exConstraints() const 98 { 99 Vector!string oids = m_info.get("X509v3.ExtendedKeyUsage"); 100 101 Vector!OID result; 102 foreach (oid; oids[]) 103 result.pushBack(OID(oid)); 104 return result; 105 } 106 107 /** 108 * Find out whether this is a CA request. 109 * Returns: true if it is a CA request, false otherwise. 110 */ 111 bool isCA() const 112 { 113 return (m_info.get1Uint("X509v3.BasicConstraints.is_ca") > 0); 114 } 115 116 117 /** 118 * Return the constraint on the path length defined 119 * in the BasicConstraints extension. 120 * Returns: the desired path limit (if any) 121 */ 122 uint pathLimit() const 123 { 124 return m_info.get1Uint("X509v3.BasicConstraints.path_constraint", 0); 125 } 126 127 /** 128 * Get the challenge password for this request 129 * Returns: challenge password for this request 130 */ 131 string challengePassword() const 132 { 133 return m_info.get1("PKCS9.ChallengePassword"); 134 } 135 136 /** 137 * Create a PKCS#10 Request from a data source. 138 * 139 * Params: 140 * source = the data source providing the DER encoded request 141 */ 142 this(DataSource source) 143 { 144 super(source, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST"); 145 doDecode(); 146 } 147 148 /** 149 * Create a PKCS#10 Request from a file. 150 * 151 * Params: 152 * input = the name of the file containing the DER or PEM encoded request file 153 */ 154 this(in string input) 155 { 156 super(input, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST"); 157 doDecode(); 158 } 159 160 /** 161 * Create a PKCS#10 Request from binary data. 162 * 163 * Params: 164 * input = a $(D Vector) containing the DER value 165 */ 166 this(ALLOC)(in Vector!(ubyte, ALLOC)* input) 167 { 168 super(*input, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST"); 169 doDecode(); 170 } 171 protected: 172 /* 173 * Deocde the CertificateRequestInfo 174 */ 175 override void forceDecode() 176 { 177 //logTrace("ForceDecode PKCS10Request"); 178 BERDecoder cert_req_info = BERDecoder(m_tbs_bits); 179 180 size_t _version; 181 cert_req_info.decode(_version); 182 if (_version != 0) 183 throw new DecodingError("Unknown version code in PKCS #10 request: " ~ to!string(_version)); 184 185 X509DN dn_subject = X509DN(); 186 cert_req_info.decode(dn_subject); 187 188 m_info.add(dn_subject.contents()); 189 190 BERObject public_key = cert_req_info.getNextObject(); 191 if (public_key.type_tag != ASN1Tag.SEQUENCE || public_key.class_tag != ASN1Tag.CONSTRUCTED) 192 throw new BERBadTag("PKCS10Request: Unexpected tag for public key", 193 public_key.type_tag, public_key.class_tag); 194 195 m_info.add("X509.Certificate.public_key", 196 PEM.encode(putInSequence(unlock(public_key.value)), "PUBLIC KEY")); 197 198 BERObject attr_bits = cert_req_info.getNextObject(); 199 200 if (attr_bits.type_tag == 0 && 201 attr_bits.class_tag == (ASN1Tag.CONSTRUCTED | ASN1Tag.CONTEXT_SPECIFIC)) 202 { 203 auto attributes = BERDecoder(attr_bits.value); 204 while (attributes.moreItems()) 205 { 206 auto attr = Attribute(); 207 attributes.decode(attr); 208 handleAttribute(attr); 209 } 210 attributes.verifyEnd(); 211 } 212 else if (attr_bits.type_tag != ASN1Tag.NO_OBJECT) 213 throw new BERBadTag("PKCS10Request: Unexpected tag for attributes", 214 attr_bits.type_tag, attr_bits.class_tag); 215 216 cert_req_info.verifyEnd(); 217 Unique!PublicKey pubkey = subjectPublicKey(); 218 if (!this.checkSignature(*pubkey)) 219 throw new DecodingError("PKCS #10 request: Bad signature detected"); 220 } 221 222 /* 223 * Handle attributes in a PKCS #10 request 224 */ 225 void handleAttribute(in Attribute attr) 226 { 227 auto value = BERDecoder(attr.parameters); 228 229 if (attr.oid == OIDS.lookup("PKCS9.EmailAddress")) 230 { 231 ASN1String email; 232 value.decode(email); 233 m_info.add("RFC822", email.value()); 234 } 235 else if (attr.oid == OIDS.lookup("PKCS9.ChallengePassword")) 236 { 237 ASN1String challenge_password; 238 value.decode(challenge_password); 239 m_info.add("PKCS9.ChallengePassword", challenge_password.value()); 240 } 241 else if (attr.oid == OIDS.lookup("PKCS9.ExtensionRequest")) 242 { 243 X509Extensions extensions; 244 value.decode(extensions).verifyEnd(); 245 246 DataStore issuer_info; 247 extensions.contentsTo(m_info, issuer_info); 248 } 249 } 250 251 252 DataStore m_info; 253 }