]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/gadgets.cc
Merged from trunk rev.14625
[thirdparty/squid.git] / src / ssl / gadgets.cc
CommitLineData
bbc27441 1/*
ef57eb7b 2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
f7f3304a 9#include "squid.h"
95d2589c 10#include "ssl/gadgets.h"
cb4f4424 11
a594dbfa
CT
12#if HAVE_OPENSSL_X509V3_H
13#include <openssl/x509v3.h>
14#endif
95d2589c 15
95d2589c
CT
16EVP_PKEY * Ssl::createSslPrivateKey()
17{
18 Ssl::EVP_PKEY_Pointer pkey(EVP_PKEY_new());
19
20 if (!pkey)
21 return NULL;
22
23 Ssl::RSA_Pointer rsa(RSA_generate_key(1024, RSA_F4, NULL, NULL));
24
25 if (!rsa)
26 return NULL;
27
28 if (!EVP_PKEY_assign_RSA(pkey.get(), (rsa.get())))
29 return NULL;
30
31 rsa.release();
32 return pkey.release();
33}
34
95d2589c
CT
35/**
36 \ingroup ServerProtocolSSLInternal
37 * Set serial random serial number or set random serial number.
38 */
39static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const* serial)
40{
41 if (!ai)
42 return false;
43 Ssl::BIGNUM_Pointer bn(BN_new());
44 if (serial) {
45 bn.reset(BN_dup(serial));
46 } else {
47 if (!bn)
48 return false;
49
50 if (!BN_pseudo_rand(bn.get(), 64, 0, 0))
51 return false;
52 }
53
54 if (ai && !BN_to_ASN1_INTEGER(bn.get(), ai))
55 return false;
56 return true;
57}
58
f97700a0 59bool Ssl::writeCertAndPrivateKeyToMemory(Security::CertPointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, std::string & bufferToWrite)
95d2589c
CT
60{
61 bufferToWrite.clear();
62 if (!pkey || !cert)
63 return false;
64 BIO_Pointer bio(BIO_new(BIO_s_mem()));
65 if (!bio)
66 return false;
67
68 if (!PEM_write_bio_X509 (bio.get(), cert.get()))
69 return false;
70
71 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
72 return false;
73
74 char *ptr = NULL;
75 long len = BIO_get_mem_data(bio.get(), &ptr);
76 if (!ptr)
77 return false;
78
79 bufferToWrite = std::string(ptr, len);
80 return true;
81}
82
f97700a0 83bool Ssl::appendCertToMemory(Security::CertPointer const & cert, std::string & bufferToWrite)
9a90aace
CT
84{
85 if (!cert)
86 return false;
87
88 BIO_Pointer bio(BIO_new(BIO_s_mem()));
89 if (!bio)
90 return false;
91
92 if (!PEM_write_bio_X509 (bio.get(), cert.get()))
93 return false;
94
95 char *ptr = NULL;
96 long len = BIO_get_mem_data(bio.get(), &ptr);
97 if (!ptr)
98 return false;
99
87f237a9 100 if (!bufferToWrite.empty())
9a90aace
CT
101 bufferToWrite.append(" "); // add a space...
102
103 bufferToWrite.append(ptr, len);
104 return true;
105}
106
f97700a0 107bool Ssl::writeCertAndPrivateKeyToFile(Security::CertPointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, char const * filename)
95d2589c
CT
108{
109 if (!pkey || !cert)
110 return false;
111
112 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
113 if (!bio)
114 return false;
115 if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
116 return false;
117
118 if (!PEM_write_bio_X509(bio.get(), cert.get()))
119 return false;
120
121 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
122 return false;
123
124 return true;
125}
126
f97700a0 127bool Ssl::readCertAndPrivateKeyFromMemory(Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * bufferToRead)
95d2589c
CT
128{
129 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
130 BIO_puts(bio.get(), bufferToRead);
131
132 X509 * certPtr = NULL;
133 cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
134 if (!cert)
135 return false;
136
137 EVP_PKEY * pkeyPtr = NULL;
138 pkey.reset(PEM_read_bio_PrivateKey(bio.get(), &pkeyPtr, 0, 0));
139 if (!pkey)
140 return false;
141
142 return true;
143}
144
f97700a0 145bool Ssl::readCertFromMemory(Security::CertPointer & cert, char const * bufferToRead)
9a90aace
CT
146{
147 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
148 BIO_puts(bio.get(), bufferToRead);
149
150 X509 * certPtr = NULL;
151 cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
152 if (!cert)
153 return false;
154
155 return true;
156}
157
bf94620c
CT
158// According to RFC 5280 (Section A.1), the common name length in a certificate
159// can be at most 64 characters
160static const size_t MaxCnLen = 64;
161
fb2178bb 162// Replace certs common name with the given
f97700a0 163static bool replaceCommonName(Security::CertPointer & cert, std::string const &rawCn)
fb2178bb 164{
4a962df3
AR
165 std::string cn = rawCn;
166
bf94620c
CT
167 if (cn.length() > MaxCnLen) {
168 // In the case the length od CN is more than the maximum supported size
169 // try to use the first upper level domain.
170 size_t pos = 0;
171 do {
172 pos = cn.find('.', pos + 1);
87f237a9 173 } while (pos != std::string::npos && (cn.length() - pos + 2) > MaxCnLen);
bf94620c
CT
174
175 // If no short domain found or this domain is a toplevel domain
176 // we failed to find a good cn name.
177 if (pos == std::string::npos || cn.find('.', pos + 1) == std::string::npos)
178 return false;
179
4a962df3 180 std::string fixedCn(1, '*');
bf94620c 181 fixedCn.append(cn.c_str() + pos);
4a962df3 182 cn = fixedCn;
bf94620c
CT
183 }
184
4a962df3
AR
185 // Assume [] surround an IPv6 address and strip them because browsers such
186 // as Firefox, Chromium, and Safari prefer bare IPv6 addresses in CNs.
187 if (cn.length() > 2 && *cn.begin() == '[' && *cn.rbegin() == ']')
188 cn = cn.substr(1, cn.size()-2);
189
fb2178bb
CT
190 X509_NAME *name = X509_get_subject_name(cert.get());
191 if (!name)
192 return false;
193 // Remove the CN part:
194 int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
aebe6888
CT
195 if (loc >=0) {
196 X509_NAME_ENTRY *tmp = X509_NAME_get_entry(name, loc);
197 X509_NAME_delete_entry(name, loc);
198 X509_NAME_ENTRY_free(tmp);
199 }
fb2178bb
CT
200
201 // Add a new CN
202 return X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
4a962df3 203 (unsigned char *)(cn.c_str()), -1, -1, 0);
fb2178bb
CT
204}
205
aebe6888
CT
206const char *Ssl::CertSignAlgorithmStr[] = {
207 "signTrusted",
87f237a9 208 "signUntrusted",
aebe6888
CT
209 "signSelf",
210 NULL
211};
212
fb2178bb
CT
213const char *Ssl::CertAdaptAlgorithmStr[] = {
214 "setValidAfter",
215 "setValidBefore",
216 "setCommonName",
217 NULL
218};
219
a0b971d5 220Ssl::CertificateProperties::CertificateProperties():
f53969cc
SM
221 setValidAfter(false),
222 setValidBefore(false),
223 setCommonName(false),
224 signAlgorithm(Ssl::algSignEnd),
225 signHash(NULL)
aebe6888
CT
226{}
227
06997a38
CT
228std::string & Ssl::CertificateProperties::dbKey() const
229{
230 static std::string certKey;
7fc31d31 231 certKey.clear();
06997a38
CT
232 certKey.reserve(4096);
233 if (mimicCert.get()) {
234 char buf[1024];
7fc31d31 235 certKey.append(X509_NAME_oneline(X509_get_subject_name(mimicCert.get()), buf, sizeof(buf)));
06997a38
CT
236 }
237
7fc31d31
AR
238 if (certKey.empty()) {
239 certKey.append("/CN=", 4);
240 certKey.append(commonName);
241 }
06997a38
CT
242
243 if (setValidAfter)
244 certKey.append("+SetValidAfter=on", 17);
245
246 if (setValidBefore)
247 certKey.append("+SetValidBefore=on", 18);
248
249 if (setCommonName) {
250 certKey.append("+SetCommonName=", 15);
251 certKey.append(commonName);
252 }
253
254 if (signAlgorithm != Ssl::algSignEnd) {
255 certKey.append("+Sign=", 6);
256 certKey.append(certSignAlgorithm(signAlgorithm));
257 }
258
3c26b00a
CT
259 if (signHash != NULL) {
260 certKey.append("+SignHash=", 10);
261 certKey.append(EVP_MD_name(signHash));
262 }
263
06997a38
CT
264 return certKey;
265}
266
5c80eab2
CT
267/// Copy certificate extensions from cert to mimicCert.
268/// Returns the number of extensions copied.
bee6354e
CT
269// Currently only extensions which are reported by the users that required are
270// mimicked. More safe to mimic extensions would be added here if users request
271// them.
5c80eab2 272static int
f97700a0 273mimicExtensions(Security::CertPointer & cert, Security::CertPointer const & mimicCert)
bee6354e
CT
274{
275 static int extensions[]= {
276 NID_key_usage,
dcc9214e 277 NID_ext_key_usage,
bee6354e
CT
278 NID_basic_constraints,
279 0
280 };
281
789bf810
CT
282 // key usage bit names
283 enum {
284 DigitalSignature,
285 NonRepudiation,
286 KeyEncipherment, // NSS requires for RSA but not EC
287 DataEncipherment,
288 KeyAgreement,
289 KeyCertificateSign,
290 CRLSign,
291 EncipherOnly,
292 DecipherOnly
293 };
294
295 int mimicAlgo = OBJ_obj2nid(mimicCert.get()->cert_info->key->algor->algorithm);
296
5c80eab2 297 int added = 0;
bee6354e
CT
298 int nid;
299 for (int i = 0; (nid = extensions[i]) != 0; ++i) {
300 const int pos = X509_get_ext_by_NID(mimicCert.get(), nid, -1);
789bf810
CT
301 if (X509_EXTENSION *ext = X509_get_ext(mimicCert.get(), pos)) {
302 // Mimic extension exactly.
5c80eab2
CT
303 if (X509_add_ext(cert.get(), ext, -1))
304 ++added;
789bf810
CT
305 if ( nid == NID_key_usage && mimicAlgo != NID_rsaEncryption ) {
306 // NSS does not requre the KeyEncipherment flag on EC keys
307 // but it does require it for RSA keys. Since ssl-bump
308 // substitutes RSA keys for EC ones, we need to ensure that
309 // that the more stringent requirements are met.
310
311 const int p = X509_get_ext_by_NID(cert.get(), NID_key_usage, -1);
312 if ((ext = X509_get_ext(cert.get(), p)) != NULL) {
313 ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING *)X509V3_EXT_d2i(ext);
314 ASN1_BIT_STRING_set_bit(keyusage, KeyEncipherment, 1);
e061c75e
CT
315
316 //Build the ASN1_OCTET_STRING
317 const X509V3_EXT_METHOD *method = X509V3_EXT_get(ext);
318 assert(method && method->it);
319 unsigned char *ext_der = NULL;
320 int ext_len = ASN1_item_i2d((ASN1_VALUE *)keyusage,
f53969cc 321 &ext_der,
e061c75e
CT
322 (const ASN1_ITEM *)ASN1_ITEM_ptr(method->it));
323
324 ASN1_OCTET_STRING *ext_oct = M_ASN1_OCTET_STRING_new();
325 ext_oct->data = ext_der;
326 ext_oct->length = ext_len;
327 X509_EXTENSION_set_data(ext, ext_oct);
328
329 M_ASN1_OCTET_STRING_free(ext_oct);
789bf810
CT
330 ASN1_BIT_STRING_free(keyusage);
331 }
332 }
333 }
bee6354e
CT
334 }
335
336 // We could also restrict mimicking of the CA extension to CA:FALSE
337 // because Squid does not generate valid fake CA certificates.
5c80eab2
CT
338
339 return added;
bee6354e
CT
340}
341
f97700a0 342static bool buildCertificate(Security::CertPointer & cert, Ssl::CertificateProperties const &properties)
87f237a9 343{
9a90aace
CT
344 // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
345 // returns a pointer to the existing subject name. Nothing to clean here.
aebe6888 346 if (properties.mimicCert.get()) {
0d57adf9
CT
347 // Leave subject empty if we cannot extract it from true cert.
348 if (X509_NAME *name = X509_get_subject_name(properties.mimicCert.get())) {
87f237a9 349 // X509_set_subject_name will call X509_dup for name
5367d845
CT
350 X509_set_subject_name(cert.get(), name);
351 }
aebe6888
CT
352 }
353
354 if (properties.setCommonName || !properties.mimicCert.get()) {
355 // In this case the CN of the certificate given by the user
bf94620c 356 // Ignore errors: it is better to make a certificate with no CN
051da40c 357 // than to quit ssl-crtd helper because we cannot make a certificate.
bf94620c
CT
358 // Most errors are caused by user input such as huge domain names.
359 (void)replaceCommonName(cert, properties.commonName);
fb2178bb 360 }
9a90aace 361
87f237a9 362 // We should get caCert notBefore and notAfter fields and do not allow
9a90aace
CT
363 // notBefore/notAfter values from certToMimic before/after notBefore/notAfter
364 // fields from caCert.
87f237a9 365 // Currently there is not any way in openssl tollkit to compare two ASN1_TIME
9a90aace 366 // objects.
fb2178bb 367 ASN1_TIME *aTime = NULL;
aebe6888
CT
368 if (!properties.setValidBefore && properties.mimicCert.get())
369 aTime = X509_get_notBefore(properties.mimicCert.get());
370 if (!aTime && properties.signWithX509.get())
371 aTime = X509_get_notBefore(properties.signWithX509.get());
fb2178bb
CT
372
373 if (aTime) {
9a90aace
CT
374 if (!X509_set_notBefore(cert.get(), aTime))
375 return false;
87f237a9 376 } else if (!X509_gmtime_adj(X509_get_notBefore(cert.get()), (-2)*24*60*60))
9a90aace
CT
377 return false;
378
fb2178bb 379 aTime = NULL;
aebe6888
CT
380 if (!properties.setValidAfter && properties.mimicCert.get())
381 aTime = X509_get_notAfter(properties.mimicCert.get());
382 if (!aTime && properties.signWithX509.get())
383 aTime = X509_get_notAfter(properties.signWithX509.get());
fb2178bb 384 if (aTime) {
9a90aace 385 if (!X509_set_notAfter(cert.get(), aTime))
b0137cd1 386 return false;
9a90aace 387 } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
b0137cd1 388 return false;
9a90aace 389
ad88633d 390 // mimic the alias and possibly subjectAltName
aebe6888
CT
391 if (properties.mimicCert.get()) {
392 unsigned char *alStr;
393 int alLen;
394 alStr = X509_alias_get0(properties.mimicCert.get(), &alLen);
395 if (alStr) {
396 X509_alias_set1(cert.get(), alStr, alLen);
397 }
398
5c80eab2
CT
399 int addedExtensions = 0;
400
ad88633d
AR
401 // Mimic subjectAltName unless we used a configured CN: browsers reject
402 // certificates with CN unrelated to subjectAltNames.
3b7ed55f 403 if (!properties.setCommonName) {
3b7ed55f 404 int pos=X509_get_ext_by_NID (properties.mimicCert.get(), OBJ_sn2nid("subjectAltName"), -1);
87f237a9 405 X509_EXTENSION *ext=X509_get_ext(properties.mimicCert.get(), pos);
4a874fbd 406 if (ext) {
5c80eab2
CT
407 if (X509_add_ext(cert.get(), ext, -1))
408 ++addedExtensions;
4a874fbd 409 }
3b7ed55f 410 }
bee6354e 411
5c80eab2
CT
412 addedExtensions += mimicExtensions(cert, properties.mimicCert);
413
414 // According to RFC 5280, using extensions requires v3 certificate.
415 if (addedExtensions)
416 X509_set_version(cert.get(), 2); // value 2 means v3
aebe6888 417 }
9a90aace
CT
418
419 return true;
420}
421
f97700a0 422static bool generateFakeSslCertificate(Security::CertPointer & certToStore, Ssl::EVP_PKEY_Pointer & pkeyToStore, Ssl::CertificateProperties const &properties, Ssl::BIGNUM_Pointer const &serial)
9a90aace 423{
aebe6888 424 Ssl::EVP_PKEY_Pointer pkey;
95588170
CT
425 // Use signing certificates private key as generated certificate private key
426 if (properties.signWithPkey.get())
154c2695 427 pkey.reset(properties.signWithPkey.get());
95588170 428 else // if not exist generate one
a0b971d5 429 pkey.reset(Ssl::createSslPrivateKey());
95588170 430
9a90aace
CT
431 if (!pkey)
432 return false;
433
f97700a0 434 Security::CertPointer cert(X509_new());
9a90aace
CT
435 if (!cert)
436 return false;
437
438 // Set pub key and serial given by the caller
439 if (!X509_set_pubkey(cert.get(), pkey.get()))
440 return false;
a0b971d5 441 if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial.get()))
9a90aace
CT
442 return false;
443
aebe6888
CT
444 // Fill the certificate with the required properties
445 if (!buildCertificate(cert, properties))
9a90aace
CT
446 return false;
447
aebe6888 448 int ret = 0;
9a90aace 449 // Set issuer name, from CA or our subject name for self signed cert
aebe6888
CT
450 if (properties.signAlgorithm != Ssl::algSignSelf && properties.signWithX509.get())
451 ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(properties.signWithX509.get()));
452 else // Self signed certificate, set issuer to self
453 ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(cert.get()));
454 if (!ret)
9a90aace
CT
455 return false;
456
3c26b00a
CT
457 const EVP_MD *hash = properties.signHash ? properties.signHash : EVP_get_digestbyname(SQUID_SSL_SIGN_HASH_IF_NONE);
458 assert(hash);
9a90aace 459 /*Now sign the request */
aebe6888 460 if (properties.signAlgorithm != Ssl::algSignSelf && properties.signWithPkey.get())
3c26b00a 461 ret = X509_sign(cert.get(), properties.signWithPkey.get(), hash);
9a90aace 462 else //else sign with self key (self signed request)
3c26b00a 463 ret = X509_sign(cert.get(), pkey.get(), hash);
9a90aace
CT
464
465 if (!ret)
466 return false;
467
468 certToStore.reset(cert.release());
aebe6888 469 pkeyToStore.reset(pkey.release());
9a90aace
CT
470 return true;
471}
472
4ece76b2
CT
473static BIGNUM *createCertSerial(unsigned char *md, unsigned int n)
474{
87f237a9 475
4ece76b2
CT
476 assert(n == 20); //for sha1 n is 20 (for md5 n is 16)
477
478 BIGNUM *serial = NULL;
479 serial = BN_bin2bn(md, n, NULL);
480
481 // if the serial is "0" set it to '1'
b9bb9562 482 if (BN_is_zero(serial) == true)
4ece76b2
CT
483 BN_one(serial);
484
c5bd24d6
CT
485 // serial size does not exceed 20 bytes
486 assert(BN_num_bits(serial) <= 160);
487
4ece76b2
CT
488 // According the RFC 5280, serial is an 20 bytes ASN.1 INTEGER (a signed big integer)
489 // and the maximum value for X.509 certificate serial number is 2^159-1 and
490 // the minimum 0. If the first bit of the serial is '1' ( eg 2^160-1),
491 // will result to a negative integer.
492 // To handle this, if the produced serial is greater than 2^159-1
493 // truncate the last bit
494 if (BN_is_bit_set(serial, 159))
495 BN_clear_bit(serial, 159);
496
497 return serial;
498}
499
a0b971d5
CT
500/// Return the SHA1 digest of the DER encoded version of the certificate
501/// stored in a BIGNUM
f97700a0 502static BIGNUM *x509Digest(Security::CertPointer const & cert)
a0b971d5
CT
503{
504 unsigned int n;
505 unsigned char md[EVP_MAX_MD_SIZE];
506
507 if (!X509_digest(cert.get(),EVP_sha1(),md,&n))
508 return NULL;
509
4ece76b2
CT
510 return createCertSerial(md, n);
511}
512
f97700a0 513static BIGNUM *x509Pubkeydigest(Security::CertPointer const & cert)
4ece76b2
CT
514{
515 unsigned int n;
516 unsigned char md[EVP_MAX_MD_SIZE];
517
518 if (!X509_pubkey_digest(cert.get(),EVP_sha1(),md,&n))
519 return NULL;
a0b971d5 520
4ece76b2 521 return createCertSerial(md, n);
a0b971d5
CT
522}
523
87f237a9
A
524/// Generate a unique serial number based on a Ssl::CertificateProperties object
525/// for a new generated certificate
a0b971d5
CT
526static bool createSerial(Ssl::BIGNUM_Pointer &serial, Ssl::CertificateProperties const &properties)
527{
528 Ssl::EVP_PKEY_Pointer fakePkey;
f97700a0 529 Security::CertPointer fakeCert;
a0b971d5 530
4ece76b2 531 serial.reset(x509Pubkeydigest(properties.signWithX509));
5cc307f3
CT
532 if (!serial.get()) {
533 serial.reset(BN_new());
0e62e0d6 534 BN_zero(serial.get());
5cc307f3 535 }
4ece76b2 536
a0b971d5
CT
537 if (!generateFakeSslCertificate(fakeCert, fakePkey, properties, serial))
538 return false;
539
540 // The x509Fingerprint return an SHA1 hash.
541 // both SHA1 hash and maximum serial number size are 20 bytes.
4ece76b2 542 BIGNUM *r = x509Digest(fakeCert);
a0b971d5
CT
543 if (!r)
544 return false;
545
a0b971d5
CT
546 serial.reset(r);
547 return true;
548}
549
f97700a0 550bool Ssl::generateSslCertificate(Security::CertPointer & certToStore, Ssl::EVP_PKEY_Pointer & pkeyToStore, Ssl::CertificateProperties const &properties)
a0b971d5
CT
551{
552 Ssl::BIGNUM_Pointer serial;
553
554 if (!createSerial(serial, properties))
555 return false;
556
557 return generateFakeSslCertificate(certToStore, pkeyToStore, properties, serial);
558}
559
95d2589c
CT
560/**
561 \ingroup ServerProtocolSSLInternal
562 * Read certificate from file.
563 */
564static X509 * readSslX509Certificate(char const * certFilename)
565{
566 if (!certFilename)
567 return NULL;
568 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
569 if (!bio)
570 return NULL;
571 if (!BIO_read_filename(bio.get(), certFilename))
572 return NULL;
573 X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
574 return certificate;
575}
576
780b55ee 577EVP_PKEY * Ssl::readSslPrivateKey(char const * keyFilename, pem_password_cb *passwd_callback)
95d2589c
CT
578{
579 if (!keyFilename)
580 return NULL;
581 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
582 if (!bio)
583 return NULL;
584 if (!BIO_read_filename(bio.get(), keyFilename))
585 return NULL;
780b55ee 586 EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio.get(), NULL, passwd_callback, NULL);
95d2589c
CT
587 return pkey;
588}
589
f97700a0 590void Ssl::readCertAndPrivateKeyFromFiles(Security::CertPointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename)
95d2589c
CT
591{
592 if (keyFilename == NULL)
593 keyFilename = certFilename;
594 pkey.reset(readSslPrivateKey(keyFilename));
595 cert.reset(readSslX509Certificate(certFilename));
596 if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
597 pkey.reset(NULL);
598 cert.reset(NULL);
599 }
600}
601
602bool Ssl::sslDateIsInTheFuture(char const * date)
603{
604 ASN1_UTCTIME tm;
605 tm.flags = 0;
606 tm.type = 23;
607 tm.data = (unsigned char *)date;
608 tm.length = strlen(date);
609
610 return (X509_cmp_current_time(&tm) > 0);
611}
e7bcc25f
CT
612
613/// Print the time represented by a ASN1_TIME struct to a string using GeneralizedTime format
614static bool asn1timeToGeneralizedTimeStr(ASN1_TIME *aTime, char *buf, int bufLen)
615{
87f237a9 616 // ASN1_Time holds time to UTCTime or GeneralizedTime form.
e7bcc25f
CT
617 // UTCTime has the form YYMMDDHHMMSS[Z | [+|-]offset]
618 // GeneralizedTime has the form YYYYMMDDHHMMSS[Z | [+|-] offset]
619
620 // length should have space for data plus 2 extra bytes for the two extra year fields
621 // plus the '\0' char.
622 if ((aTime->length + 3) > bufLen)
623 return false;
624
625 char *str;
626 if (aTime->type == V_ASN1_UTCTIME) {
627 if (aTime->data[0] > '5') { // RFC 2459, section 4.1.2.5.1
628 buf[0] = '1';
629 buf[1] = '9';
630 } else {
631 buf[0] = '2';
632 buf[1] = '0';
633 }
634 str = buf +2;
87f237a9 635 } else // if (aTime->type == V_ASN1_GENERALIZEDTIME)
e7bcc25f
CT
636 str = buf;
637
638 memcpy(str, aTime->data, aTime->length);
639 str[aTime->length] = '\0';
640 return true;
641}
642
643static int asn1time_cmp(ASN1_TIME *asnTime1, ASN1_TIME *asnTime2)
644{
645 char strTime1[64], strTime2[64];
646 if (!asn1timeToGeneralizedTimeStr(asnTime1, strTime1, sizeof(strTime1)))
647 return -1;
648 if (!asn1timeToGeneralizedTimeStr(asnTime2, strTime2, sizeof(strTime2)))
649 return -1;
87f237a9 650
e7bcc25f
CT
651 return strcmp(strTime1, strTime2);
652}
653
4ece76b2 654bool Ssl::certificateMatchesProperties(X509 *cert, CertificateProperties const &properties)
e7bcc25f 655{
4ece76b2
CT
656 assert(cert);
657
658 // For non self-signed certificates we have to check if the signing certificate changed
659 if (properties.signAlgorithm != Ssl::algSignSelf) {
f4e4d4d6 660 assert(properties.signWithX509.get());
4ece76b2
CT
661 if (X509_check_issued(properties.signWithX509.get(), cert) != X509_V_OK)
662 return false;
663 }
87f237a9 664
4ece76b2
CT
665 X509 *cert2 = properties.mimicCert.get();
666 // If there is not certificate to mimic stop here
667 if (!cert2)
668 return true;
669
670 if (!properties.setCommonName) {
671 X509_NAME *cert1_name = X509_get_subject_name(cert);
672 X509_NAME *cert2_name = X509_get_subject_name(cert2);
673 if (X509_NAME_cmp(cert1_name, cert2_name) != 0)
674 return false;
87f237a9
A
675 } else if (properties.commonName != CommonHostName(cert))
676 return false;
677
4ece76b2
CT
678 if (!properties.setValidBefore) {
679 ASN1_TIME *aTime = X509_get_notBefore(cert);
680 ASN1_TIME *bTime = X509_get_notBefore(cert2);
681 if (asn1time_cmp(aTime, bTime) != 0)
682 return false;
0efa4d01
CT
683 } else if (X509_cmp_current_time(X509_get_notBefore(cert)) >= 0) {
684 // notBefore does not exist (=0) or it is in the future (>0)
685 return false;
4ece76b2 686 }
e7bcc25f 687
4ece76b2
CT
688 if (!properties.setValidAfter) {
689 ASN1_TIME *aTime = X509_get_notAfter(cert);
690 ASN1_TIME *bTime = X509_get_notAfter(cert2);
691 if (asn1time_cmp(aTime, bTime) != 0)
692 return false;
0efa4d01
CT
693 } else if (X509_cmp_current_time(X509_get_notAfter(cert)) <= 0) {
694 // notAfter does not exist (0) or it is in the past (<0)
695 return false;
4ece76b2 696 }
0efa4d01 697
e7bcc25f
CT
698 char *alStr1;
699 int alLen;
4ece76b2 700 alStr1 = (char *)X509_alias_get0(cert, &alLen);
e7bcc25f
CT
701 char *alStr2 = (char *)X509_alias_get0(cert2, &alLen);
702 if ((!alStr1 && alStr2) || (alStr1 && !alStr2) ||
87f237a9 703 (alStr1 && alStr2 && strcmp(alStr1, alStr2)) != 0)
e7bcc25f 704 return false;
87f237a9 705
e7bcc25f
CT
706 // Compare subjectAltName extension
707 STACK_OF(GENERAL_NAME) * cert1_altnames;
4ece76b2 708 cert1_altnames = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
e7bcc25f
CT
709 STACK_OF(GENERAL_NAME) * cert2_altnames;
710 cert2_altnames = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert2, NID_subject_alt_name, NULL, NULL);
711 bool match = true;
712 if (cert1_altnames) {
713 int numalts = sk_GENERAL_NAME_num(cert1_altnames);
a38ec4b1 714 for (int i = 0; match && i < numalts; ++i) {
e7bcc25f
CT
715 const GENERAL_NAME *aName = sk_GENERAL_NAME_value(cert1_altnames, i);
716 match = sk_GENERAL_NAME_find(cert2_altnames, aName);
717 }
87f237a9 718 } else if (cert2_altnames)
e7bcc25f 719 match = false;
87f237a9 720
e7bcc25f
CT
721 sk_GENERAL_NAME_pop_free(cert1_altnames, GENERAL_NAME_free);
722 sk_GENERAL_NAME_pop_free(cert2_altnames, GENERAL_NAME_free);
723
724 return match;
725}
0efa4d01
CT
726
727static const char *getSubjectEntry(X509 *x509, int nid)
728{
729 static char name[1024] = ""; // stores common name (CN)
730
731 if (!x509)
732 return NULL;
733
734 // TODO: What if the entry is a UTF8String? See X509_NAME_get_index_by_NID(3ssl).
735 const int nameLen = X509_NAME_get_text_by_NID(
87f237a9
A
736 X509_get_subject_name(x509),
737 nid, name, sizeof(name));
0efa4d01
CT
738
739 if (nameLen > 0)
740 return name;
741
742 return NULL;
743}
744
745const char *Ssl::CommonHostName(X509 *x509)
746{
747 return getSubjectEntry(x509, NID_commonName);
748}
749
750const char *Ssl::getOrganization(X509 *x509)
751{
752 return getSubjectEntry(x509, NID_organizationName);
753}
754