1 /**
2 * X.509 Certificates
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.x509cert;
12 
13 import botan.constants;
14 version(X509):
15 public import botan.utils.datastor.datastor;
16 public import botan.pubkey.x509_key;
17 public import botan.cert.x509.x509_obj;
18 public import botan.asn1.x509_dn;
19 public import botan.cert.x509.certstor;
20 import botan.cert.x509.key_constraint : KeyConstraints;
21 import botan.cert.x509.x509_ext;
22 import botan.codec.pem;
23 import botan.codec.hex;
24 import botan.asn1.asn1_alt_name;
25 import botan.asn1.der_enc;
26 import botan.asn1.ber_dec;
27 import botan.asn1.oids;
28 import botan.asn1.asn1_time;
29 import botan.libstate.lookup;
30 import botan.math.bigint.bigint;
31 import botan.utils.types;
32 import memutils.refcounted;
33 import memutils.dictionarylist;
34 import memutils.hashmap;
35 import botan.utils.parsing;
36 import botan.utils.types : Vector, RefCounted;
37 import std.algorithm;
38 import std.array : Appender;
39 
40 
41 alias X509Certificate = RefCounted!X509CertificateImpl;
42 
43 /**
44 * This class represents X.509 Certificate
45 */
46 final class X509CertificateImpl : X509Object
47 {
48 public:
49     /**
50     * Get the public key associated with this certificate.
51     * Returns: subject public key of this certificate
52     */
53     PublicKey subjectPublicKey() const
54     {
55         Vector!ubyte keybits = subjectPublicKeyBits().clone;
56         return x509_key.loadKey(putInSequence(keybits));
57     }
58 
59     /**
60     * Get the public key associated with this certificate.
61     * Returns: subject public key of this certificate
62     */
63     const(Vector!ubyte) subjectPublicKeyBits() const
64     {
65         return hexDecode(m_subject.get1("X509.Certificate.public_key"));
66     }
67 
68     /**
69     * Get the issuer certificate DN.
70     * Returns: issuer DN of this certificate
71     */
72     const(X509DN) issuerDn() const
73     {
74         return createDn(m_issuer);
75     }
76 
77     /**
78     * Get the subject certificate DN.
79     * Returns: subject DN of this certificate
80     */
81     const(X509DN) subjectDn() const
82     {
83         return createDn(m_subject);
84     }
85 
86     /**
87     * Get a value for a specific subject_info parameter name.
88     *
89     * Params:
90     *  what = the name of the paramter to look up. Possible names are
91     * "X509.Certificate.version", "X509.Certificate.serial",
92     * "X509.Certificate.start", "X509.Certificate.end",
93     * "X509.Certificate.v2.key_id", "X509.Certificate.public_key",
94     * "X509v3.BasicConstraints.path_constraint",
95     * "X509v3.BasicConstraints.is_ca", "X509v3.ExtendedKeyUsage",
96     * "X509v3.CertificatePolicies", "X509v3.SubjectKeyIdentifier" or
97     * "X509.Certificate.serial".
98     * Returns: value(s) of the specified parameter
99     */
100     const(Vector!string) subjectInfo(in string what) const
101     {
102         return m_subject.get(X509DNImpl.derefInfoField(what));
103     }
104 
105     /**
106     * Get a value for a specific subject_info parameter name.
107     *
108     * Params:
109     *  what = the name of the paramter to look up. Possible names are
110     * "X509.Certificate.v2.key_id" or "X509v3.AuthorityKeyIdentifier".
111     * Returns: value(s) of the specified parameter
112     */
113     const(Vector!string) issuerInfo(in string what) const
114     {
115         return m_issuer.get(X509DNImpl.derefInfoField(what));
116     }
117 
118     /**
119     * Raw subject DN
120     */
121     const(Vector!ubyte) rawIssuerDn() const
122     {
123         return m_issuer.get1Memvec("X509.Certificate.dn_bits");
124     }
125 
126 
127     /**
128     * Raw issuer DN
129     */
130     const(Vector!ubyte) rawSubjectDn() const
131     {
132         return m_subject.get1Memvec("X509.Certificate.dn_bits");
133     }
134 
135     /**
136     * Get the notBefore of the certificate.
137     * Returns: notBefore of the certificate
138     */
139     string startTime() const
140     {
141         return m_subject.get1("X509.Certificate.start");
142     }
143 
144     /**
145     * Get the notAfter of the certificate.
146     * Returns: notAfter of the certificate
147     */
148     string endTime() const
149     {
150         return m_subject.get1("X509.Certificate.end");
151     }
152 
153     /**
154     * Get the X509 version of this certificate object.
155     * Returns: X509 version
156     */
157     uint x509Version() const
158     {
159         return (m_subject.get1Uint("X509.Certificate.version") + 1);
160     }
161 
162     /**
163     * Get the serial number of this certificate.
164     * Returns: certificates serial number
165     */
166     const(Vector!ubyte) serialNumber() const
167     {
168         return m_subject.get1Memvec("X509.Certificate.serial");
169     }
170 
171     /**
172     * Get the DER encoded AuthorityKeyIdentifier of this certificate.
173     * Returns: DER encoded AuthorityKeyIdentifier
174     */
175     const(Vector!ubyte) authorityKeyId() const
176     {
177         return m_issuer.get1Memvec("X509v3.AuthorityKeyIdentifier");
178     }
179 
180     /**
181     * Get the DER encoded SubjectKeyIdentifier of this certificate.
182     * Returns: DER encoded SubjectKeyIdentifier
183     */
184     const(Vector!ubyte) subjectKeyId() const
185     {
186         return m_subject.get1Memvec("X509v3.SubjectKeyIdentifier");
187     }
188 
189     /**
190     * Check whether this certificate is self signed.
191     * Returns: true if this certificate is self signed
192     */
193     bool isSelfSigned() const { return m_self_signed; }
194 
195     /**
196     * Check whether this certificate is a CA certificate.
197     * Returns: true if this certificate is a CA certificate
198     */
199     bool isCACert() const
200     {
201         if (!m_subject.get1Uint("X509v3.BasicConstraints.is_ca"))
202             return false;
203         
204         return allowedUsage(KeyConstraints.KEY_CERT_SIGN);
205     }
206 
207 
208     bool allowedUsage(KeyConstraints usage) const
209     {
210         if (constraints() == KeyConstraints.NO_CONSTRAINTS)
211             return true;
212         return cast(bool) (constraints() & usage);
213     }
214 
215     /**
216     * Returns true if and only if name (referring to an extended key
217     * constraint, eg "PKIX.ServerAuth") is included in the extended
218     * key extension.
219     */
220     bool allowedUsage(in string usage) const
221     {
222         auto constraints = exConstraints();
223         foreach (constraint; constraints[])
224             if (constraint == usage)
225                 return true;
226         
227         return false;
228     }
229 
230     /**
231     * Get the path limit as defined in the BasicConstraints extension of
232     * this certificate.
233     * Returns: path limit
234     */
235     uint pathLimit() const
236     {
237         return m_subject.get1Uint("X509v3.BasicConstraints.path_constraint", 0);
238     }
239 
240     /**
241     * Get the key constraints as defined in the KeyUsage extension of this
242     * certificate.
243     * Returns: key constraints
244     */
245     const(KeyConstraints) constraints() const
246     {
247         return cast(KeyConstraints) m_subject.get1Uint("X509v3.KeyUsage", KeyConstraints.NO_CONSTRAINTS);
248     }
249 
250     /**
251     * Get the key constraints as defined in the ExtendedKeyUsage
252     * extension of this
253     * certificate.
254     * Returns: key constraints
255     */
256     const(Vector!string) exConstraints() const
257     {
258         return lookupOids(m_subject.get("X509v3.ExtendedKeyUsage"));
259     }
260 
261     /**
262     * Get the policies as defined in the CertificatePolicies extension
263     * of this certificate.
264     * Returns: certificate policies
265     */
266     const(Vector!string) policies() const
267     {
268         return lookupOids(m_subject.get("X509v3.CertificatePolicies"));
269     }
270 
271     /**
272     * Return the listed address of an OCSP responder, or empty if not set
273     */
274     string ocspResponder() const
275     {
276         //logTrace("Find OCSP responder in DataStore: ", m_subject.toString());
277         return m_subject.get1("OCSP.responder", "");
278     }
279 
280     /**
281     * Return the CRL distribution point, or empty if not set
282     */
283     string crlDistributionPoint() const
284     {
285 		import std.range : front;
286 		auto crl_dist = m_subject.get("CRL.DistributionPoint");
287 		if (crl_dist.length)
288 			return crl_dist.front;
289 		return "";
290     }
291 
292     /**
293     * Returns: a string describing the certificate
294     */
295 
296     override string toString() const
297     {
298         import std.array : Appender;
299         __gshared immutable string[] dn_fields = [ "Name",
300             "Email",
301             "Organization",
302             "Organizational Unit",
303             "Locality",
304             "State",
305             "Country",
306             "IP",
307             "DNS",
308             "URI",
309             "PKIX.XMPPAddr" ];
310         
311         Appender!string output;
312         
313         foreach (const dn_field; dn_fields)
314         {
315             const Vector!string vals = subjectInfo(dn_field);
316             
317             if (vals.empty)
318                 continue;
319             
320             output ~= "Subject " ~ dn_field ~ ":";
321             for (size_t j = 0; j != vals.length; ++j)
322                 output ~= " " ~ vals[j];
323             output ~= "\n";
324         }
325         
326         foreach (const dn_field; dn_fields)
327         {
328             const Vector!string vals = issuerInfo(dn_field);
329             
330             if (vals.empty)
331                 continue;
332             
333             output ~= "Issuer " ~ dn_field ~ ":";
334             for (size_t j = 0; j != vals.length; ++j)
335                 output ~= " " ~ vals[j];
336             output ~= "\n";
337         }
338         
339         output ~= "\nVersion: " ~ x509Version().to!string;
340         
341         output ~= "\nNot valid before: " ~ startTime();
342         output ~= "\nNot valid after: " ~ endTime();
343         
344         output ~= "\nConstraints:";
345         KeyConstraints constraints = constraints();
346         if (constraints == KeyConstraints.NO_CONSTRAINTS)
347             output ~= " None";
348         else
349         {
350             if (constraints & KeyConstraints.DIGITAL_SIGNATURE)
351                 output ~= "\n    Digital Signature";
352             if (constraints & KeyConstraints.NON_REPUDIATION)
353                 output ~= "\n    Non-Repuidation";
354             if (constraints & KeyConstraints.KEY_ENCIPHERMENT)
355                 output ~= "\n    Key Encipherment";
356             if (constraints & KeyConstraints.DATA_ENCIPHERMENT)
357                 output ~= "\n    Data Encipherment";
358             if (constraints & KeyConstraints.KEY_AGREEMENT)
359                 output ~= "\n    Key Agreement";
360             if (constraints & KeyConstraints.KEY_CERT_SIGN)
361                 output ~= "\n    Cert Sign";
362             if (constraints & KeyConstraints.CRL_SIGN)
363                 output ~= "\n    CRL Sign";
364         }
365         
366         const Vector!string policies = policies();
367         if (!policies.empty)
368         {
369             output ~= "\nPolicies: ";
370             foreach (const policy; policies[])
371                 output ~= "    " ~ policy;
372         }
373         
374         const Vector!string ex_constraints = exConstraints();
375         if (!ex_constraints.empty)
376         {
377             output ~= "\nExtended Constraints:";
378             foreach (const ex_constraint; ex_constraints[])
379                 output ~= "    " ~ ex_constraint;
380         }
381         
382         if (ocspResponder() != "")
383             output ~= "\nOCSP responder " ~ ocspResponder();
384         if (crlDistributionPoint() != "")
385             output ~= "\nCRL " ~ crlDistributionPoint();
386         
387         output ~= "\nSignature algorithm: " ~ OIDS.lookup(signatureAlgorithm().oid);
388         
389         output ~= "\nSerial number: " ~ hexEncode(serialNumber());
390         
391         if (authorityKeyId().length)
392             output ~= "\nAuthority keyid: " ~ hexEncode(authorityKeyId());
393         
394         if (subjectKeyId().length)
395             output ~= "\nSubject keyid: " ~ hexEncode(subjectKeyId());
396         
397         Unique!X509PublicKey pubkey = subjectPublicKey();
398         output ~= "\nPublic Key:\n\n" ~ x509_key.PEM_encode(*pubkey) ~ "\n";
399         
400         return output.data;
401     }
402 
403 
404     /**
405     * Return a fingerprint of the certificate
406     */
407     string fingerprint(in string hash_name) const
408     {
409         Unique!HashFunction hash = retrieveHash(hash_name).clone();
410         hash.update(BER_encode());
411         const auto hex_print = hexEncode(hash.finished());
412         
413         Vector!char formatted_print;
414         
415         for (size_t i = 0; i != hex_print.length; i += 2)
416         {
417             formatted_print.pushBack(hex_print[i]);
418             formatted_print.pushBack(hex_print[i+1]);
419             
420             if (i != hex_print.length - 2)
421                 formatted_print.pushBack(':');
422         }
423         
424         return formatted_print[].idup;
425     }
426 
427     /**
428     * Check if a certain DNS name matches up with the information in
429     * the cert
430     */
431     bool matchesDnsName(in string name) const
432     {
433         if (name == "")
434             return false;
435         
436         if (certSubjectDnsMatch(name, subjectInfo("DNS")))
437             return true;
438         
439         if (certSubjectDnsMatch(name, subjectInfo("Name")))
440             return true;
441         
442         return false;
443     }
444 
445     /**
446     * Check to certificates for equality.
447     * Returns: true both certificates are (binary) equal
448     */
449     bool opEquals(in X509Certificate other) const
450     {
451 		if (*other is null)
452 			return false;
453         return (m_sig == other.m_sig &&
454                 m_sig_algo == other.m_sig_algo &&
455                 m_self_signed == other.m_self_signed &&
456                 m_issuer == other.m_issuer &&
457                 m_subject == other.m_subject);
458     }
459 
460     /**
461     * Impose an arbitrary (but consistent) ordering
462     * Returns: true if this is less than other by some unspecified criteria
463     */
464     bool opBinary(string op)(in X509Certificate other) const
465         if (op == "<")
466     {
467         /* If signature values are not equal, sort by lexicographic ordering of that */
468         if (sig != other.sig)
469         {
470             if (sig < other.sig)
471                 return true;
472             return false;
473         }
474         
475         // Then compare the signed contents
476         return tbs_bits < other.tbs_bits;
477     }
478 
479     /**
480     * Check two certificates for quality
481     * Returns: true if the arguments represent different certificates,
482     * false if they are binary identical
483     */
484     int opCmp(in X509Certificate cert2)
485     {
486         if (this == cert2) return 0;
487         else return -1;
488     }
489 
490     bool isValid() {
491         return !m_subject.get("X509.Certificate.start").empty;
492     }
493 
494     /**
495     * Create a certificate from a data source providing the DER or
496     * PEM encoded certificate.
497     *
498     * Params:
499     *  input = the data source
500     */
501     this(DataSource input)
502     {
503         super(input, "CERTIFICATE/X509 CERTIFICATE");
504         m_self_signed = false;
505         doDecode();
506     }
507 
508     /**
509     * Create a certificate from a file containing the DER or PEM
510     * encoded certificate.
511     *
512     * Params:
513     *  filename = the name of the certificate file
514     */
515     this(in string filename)
516     {
517         super(filename, "CERTIFICATE/X509 CERTIFICATE");
518         m_self_signed = false;
519         doDecode();
520     }
521 
522     this(ALLOC)(auto const ref Vector!(ubyte, ALLOC) input)
523     {
524         super(input, "CERTIFICATE/X509 CERTIFICATE");
525         m_self_signed = false;
526         doDecode();
527     }
528 
529     this(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) input)
530     {
531         super(input, "CERTIFICATE/X509 CERTIFICATE");
532         m_self_signed = false;
533         doDecode();
534     }
535 
536 protected:
537     /*
538     * Decode the TBSCertificate data
539     */
540     override void forceDecode()
541     {
542         size_t _version;
543         BigInt serial_bn;
544         auto sig_algo_inner = AlgorithmIdentifier();
545         X509DN dn_issuer, dn_subject;
546         import std.datetime : Clock, UTC;
547         X509Time start = X509Time(Clock.currTime(UTC()));
548         X509Time end = X509Time(Clock.currTime(UTC()));
549         
550         BERDecoder tbsCert = BERDecoder(m_tbs_bits);
551         tbsCert.decodeOptional(_version, (cast(ASN1Tag) 0),
552                               (ASN1Tag.CONSTRUCTED | ASN1Tag.CONTEXT_SPECIFIC))
553                 .decode(serial_bn)
554                 .decode(sig_algo_inner)
555                 .decode(dn_issuer)
556                 .startCons(ASN1Tag.SEQUENCE)
557                 .decode(start)
558                 .decode(end)
559                 .verifyEnd()
560                 .endCons()
561                 .decode(dn_subject);
562         
563         if (_version > 2)
564             throw new DecodingError("Unknown X.509 cert version " ~ to!string(_version));
565         if (m_sig_algo != sig_algo_inner)
566             throw new DecodingError("Algorithm identifier mismatch");
567         
568         m_self_signed = (dn_subject == dn_issuer);
569         //logTrace("Is self signed: ", m_self_signed);
570         m_subject.add(dn_subject.contents());
571         m_issuer.add(dn_issuer.contents());
572         
573         m_subject.add("X509.Certificate.dn_bits", putInSequence(dn_subject.getBits()));
574         m_issuer.add("X509.Certificate.dn_bits", putInSequence(dn_issuer.getBits()));
575         
576         BERObject public_key = tbsCert.getNextObject();
577 
578         if (public_key.type_tag != ASN1Tag.SEQUENCE || public_key.class_tag != ASN1Tag.CONSTRUCTED)
579             throw new BERBadTag("X509Certificate: Unexpected tag for public key",
580                                   public_key.type_tag, public_key.class_tag);
581         
582         Vector!ubyte v2_issuer_key_id, v2_subject_key_id;
583         
584         tbsCert.decodeOptionalString(v2_issuer_key_id, ASN1Tag.BIT_STRING, 1);
585         tbsCert.decodeOptionalString(v2_subject_key_id, ASN1Tag.BIT_STRING, 2);
586         
587         BERObject v3_exts_data = tbsCert.getNextObject();
588         if (v3_exts_data.type_tag == 3 &&
589             v3_exts_data.class_tag == (ASN1Tag.CONSTRUCTED | ASN1Tag.CONTEXT_SPECIFIC))
590         {
591             X509Extensions extensions = X509Extensions(true);
592             
593             BERDecoder(v3_exts_data.value).decode(extensions).verifyEnd();
594             
595             extensions.contentsTo(m_subject, m_issuer);
596         }
597         else if (v3_exts_data.type_tag != ASN1Tag.NO_OBJECT)
598             throw new BERBadTag("Unknown tag in X.509 cert", v3_exts_data.type_tag, v3_exts_data.class_tag);
599         
600         if (tbsCert.moreItems())
601             throw new DecodingError("TBSCertificate has more items that expected");
602         
603         m_subject.add("X509.Certificate.version", _version);
604         m_subject.add("X509.Certificate.serial", BigInt.encode(serial_bn));
605         m_subject.add("X509.Certificate.start", start.readableString());
606         m_subject.add("X509.Certificate.end", end.readableString());
607         
608         m_issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id);
609         m_subject.add("X509.Certificate.v2.key_id", v2_subject_key_id);
610         
611         m_subject.add("X509.Certificate.public_key",
612         hexEncode(public_key.value));
613         
614         if (m_self_signed && _version == 0)
615         {
616             m_subject.add("X509v3.BasicConstraints.is_ca", 1);
617             m_subject.add("X509v3.BasicConstraints.path_constraint", NO_CERT_PATH_LIMIT);
618         }
619         
620         if (isCACert() &&
621             !m_subject.hasValue("X509v3.BasicConstraints.path_constraint"))
622         {
623             const size_t limit = (x509Version() < 3) ? NO_CERT_PATH_LIMIT : 0;
624             
625             m_subject.add("X509v3.BasicConstraints.path_constraint", limit);
626         }
627 
628     }
629 
630 
631     this() {}
632 
633     DataStore m_subject, m_issuer;
634     bool m_self_signed;
635 }
636 
637 
638 /*
639 * Data Store Extraction Operations
640 */
641 /*
642 * Create and populate a X509DN
643 */
644 X509DN createDn(in DataStore info)
645 {
646     bool search_for(string key, string val)
647     {
648         return (key.canFind("X520."));
649     }
650     auto names = info.searchFor(&search_for);
651     
652     X509DN dn = X509DN();
653     
654     foreach (const ref string key, const ref string value; names)
655         dn.addAttribute(key, value);
656     
657     return dn;
658 }
659 
660 
661 /*
662 * Create and populate an AlternativeName
663 */
664 AlternativeName createAltName(in DataStore info)
665 {
666     auto names = info.searchFor((string key, string)
667                                  { return (key == "RFC822" || key == "DNS" || key == "URI" || key == "IP"); });
668     
669     AlternativeName alt_name = AlternativeName();
670     
671     foreach (const ref string key, const ref string value; names)
672         alt_name.addAttribute(key, value);
673     
674     return alt_name;
675 }
676 
677 
678 
679 /*
680 * Lookup each OID in the vector
681 */
682 Vector!string lookupOids(ALLOC)(auto const ref Vector!(string, ALLOC) input)
683 {
684     Vector!string output = Vector!string();
685     
686     foreach (oid_name; input[])
687         output.pushBack(OIDS.lookup(OID(oid_name)));
688     return output;
689 }
690 
691 
692 bool certSubjectDnsMatch(ALLOC)(in string name,
693                                      auto const ref Vector!(string, ALLOC) cert_names)
694 {
695     foreach (const cn; cert_names[])
696     {
697         if (cn == name)
698             return true;
699         
700         /*
701         * Possible wildcard match. We only support the most basic form of
702         * cert wildcarding ala RFC 2595
703         */
704         if (cn.length > 2 && cn[0] == '*' && cn[1] == '.' && name.length > cn.length)
705         {
706             const string base = cn[1 .. $];
707             size_t start = name.length - base.length;
708             if (name[start .. start + base.length] == base)
709                 return true;
710         }
711     }
712     
713     return false;
714 }