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