6 #include "ssl/gadgets.h"
7 #if HAVE_OPENSSL_X509V3_H
8 #include <openssl/x509v3.h>
11 EVP_PKEY
* Ssl::createSslPrivateKey()
13 Ssl::EVP_PKEY_Pointer
pkey(EVP_PKEY_new());
18 Ssl::RSA_Pointer
rsa(RSA_generate_key(1024, RSA_F4
, NULL
, NULL
));
23 if (!EVP_PKEY_assign_RSA(pkey
.get(), (rsa
.get())))
27 return pkey
.release();
31 \ingroup ServerProtocolSSLInternal
32 * Set serial random serial number or set random serial number.
34 static bool setSerialNumber(ASN1_INTEGER
*ai
, BIGNUM
const* serial
)
38 Ssl::BIGNUM_Pointer
bn(BN_new());
40 bn
.reset(BN_dup(serial
));
45 if (!BN_pseudo_rand(bn
.get(), 64, 0, 0))
49 if (ai
&& !BN_to_ASN1_INTEGER(bn
.get(), ai
))
54 bool Ssl::writeCertAndPrivateKeyToMemory(Ssl::X509_Pointer
const & cert
, Ssl::EVP_PKEY_Pointer
const & pkey
, std::string
& bufferToWrite
)
56 bufferToWrite
.clear();
59 BIO_Pointer
bio(BIO_new(BIO_s_mem()));
63 if (!PEM_write_bio_X509 (bio
.get(), cert
.get()))
66 if (!PEM_write_bio_PrivateKey(bio
.get(), pkey
.get(), NULL
, NULL
, 0, NULL
, NULL
))
70 long len
= BIO_get_mem_data(bio
.get(), &ptr
);
74 bufferToWrite
= std::string(ptr
, len
);
78 bool Ssl::appendCertToMemory(Ssl::X509_Pointer
const & cert
, std::string
& bufferToWrite
)
83 BIO_Pointer
bio(BIO_new(BIO_s_mem()));
87 if (!PEM_write_bio_X509 (bio
.get(), cert
.get()))
91 long len
= BIO_get_mem_data(bio
.get(), &ptr
);
95 if (!bufferToWrite
.empty())
96 bufferToWrite
.append(" "); // add a space...
98 bufferToWrite
.append(ptr
, len
);
102 bool Ssl::writeCertAndPrivateKeyToFile(Ssl::X509_Pointer
const & cert
, Ssl::EVP_PKEY_Pointer
const & pkey
, char const * filename
)
107 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_file_internal()));
110 if (!BIO_write_filename(bio
.get(), const_cast<char *>(filename
)))
113 if (!PEM_write_bio_X509(bio
.get(), cert
.get()))
116 if (!PEM_write_bio_PrivateKey(bio
.get(), pkey
.get(), NULL
, NULL
, 0, NULL
, NULL
))
122 bool Ssl::readCertAndPrivateKeyFromMemory(Ssl::X509_Pointer
& cert
, Ssl::EVP_PKEY_Pointer
& pkey
, char const * bufferToRead
)
124 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_mem()));
125 BIO_puts(bio
.get(), bufferToRead
);
127 X509
* certPtr
= NULL
;
128 cert
.reset(PEM_read_bio_X509(bio
.get(), &certPtr
, 0, 0));
132 EVP_PKEY
* pkeyPtr
= NULL
;
133 pkey
.reset(PEM_read_bio_PrivateKey(bio
.get(), &pkeyPtr
, 0, 0));
140 bool Ssl::readCertFromMemory(X509_Pointer
& cert
, char const * bufferToRead
)
142 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_mem()));
143 BIO_puts(bio
.get(), bufferToRead
);
145 X509
* certPtr
= NULL
;
146 cert
.reset(PEM_read_bio_X509(bio
.get(), &certPtr
, 0, 0));
153 // According to RFC 5280 (Section A.1), the common name length in a certificate
154 // can be at most 64 characters
155 static const size_t MaxCnLen
= 64;
157 // Replace certs common name with the given
158 static bool replaceCommonName(Ssl::X509_Pointer
& cert
, std::string
const &cn
)
161 if (cn
.length() > MaxCnLen
) {
162 // In the case the length od CN is more than the maximum supported size
163 // try to use the first upper level domain.
166 pos
= cn
.find('.', pos
+ 1);
167 } while(pos
!= std::string::npos
&& (cn
.length() - pos
+ 2) > MaxCnLen
);
169 // If no short domain found or this domain is a toplevel domain
170 // we failed to find a good cn name.
171 if (pos
== std::string::npos
|| cn
.find('.', pos
+ 1) == std::string::npos
)
174 fixedCn
.append(1,'*');
175 fixedCn
.append(cn
.c_str() + pos
);
178 X509_NAME
*name
= X509_get_subject_name(cert
.get());
181 // Remove the CN part:
182 int loc
= X509_NAME_get_index_by_NID(name
, NID_commonName
, -1);
184 X509_NAME_ENTRY
*tmp
= X509_NAME_get_entry(name
, loc
);
185 X509_NAME_delete_entry(name
, loc
);
186 X509_NAME_ENTRY_free(tmp
);
190 return X509_NAME_add_entry_by_NID(name
, NID_commonName
, MBSTRING_ASC
,
191 (unsigned char *)(fixedCn
.empty() ? cn
.c_str() : fixedCn
.c_str()), -1, -1, 0);
194 const char *Ssl::CertSignAlgorithmStr
[] = {
201 const char *Ssl::CertAdaptAlgorithmStr
[] = {
208 Ssl::CertificateProperties::CertificateProperties():
209 setValidAfter(false),
210 setValidBefore(false),
211 setCommonName(false),
212 signAlgorithm(Ssl::algSignEnd
)
215 std::string
& Ssl::CertificateProperties::dbKey() const
217 static std::string certKey
;
219 certKey
.reserve(4096);
220 if (mimicCert
.get()) {
222 certKey
.append(X509_NAME_oneline(X509_get_subject_name(mimicCert
.get()), buf
, sizeof(buf
)));
225 if (certKey
.empty()) {
226 certKey
.append("/CN=", 4);
227 certKey
.append(commonName
);
231 certKey
.append("+SetValidAfter=on", 17);
234 certKey
.append("+SetValidBefore=on", 18);
237 certKey
.append("+SetCommonName=", 15);
238 certKey
.append(commonName
);
241 if (signAlgorithm
!= Ssl::algSignEnd
) {
242 certKey
.append("+Sign=", 6);
243 certKey
.append(certSignAlgorithm(signAlgorithm
));
249 static bool buildCertificate(Ssl::X509_Pointer
& cert
, Ssl::CertificateProperties
const &properties
)
251 // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
252 // returns a pointer to the existing subject name. Nothing to clean here.
253 if (properties
.mimicCert
.get()) {
254 // Leave subject empty if we cannot extract it from true cert.
255 if (X509_NAME
*name
= X509_get_subject_name(properties
.mimicCert
.get())) {
256 // X509_set_subject_name will call X509_dup for name
257 X509_set_subject_name(cert
.get(), name
);
261 if (properties
.setCommonName
|| !properties
.mimicCert
.get()) {
262 // In this case the CN of the certificate given by the user
263 // Ignore errors: it is better to make a certificate with no CN
264 // than to quit ssl_crtd because we cannot make a certificate.
265 // Most errors are caused by user input such as huge domain names.
266 (void)replaceCommonName(cert
, properties
.commonName
);
269 // We should get caCert notBefore and notAfter fields and do not allow
270 // notBefore/notAfter values from certToMimic before/after notBefore/notAfter
271 // fields from caCert.
272 // Currently there is not any way in openssl tollkit to compare two ASN1_TIME
274 ASN1_TIME
*aTime
= NULL
;
275 if (!properties
.setValidBefore
&& properties
.mimicCert
.get())
276 aTime
= X509_get_notBefore(properties
.mimicCert
.get());
277 if (!aTime
&& properties
.signWithX509
.get())
278 aTime
= X509_get_notBefore(properties
.signWithX509
.get());
281 if (!X509_set_notBefore(cert
.get(), aTime
))
284 else if (!X509_gmtime_adj(X509_get_notBefore(cert
.get()), (-2)*24*60*60))
288 if (!properties
.setValidAfter
&& properties
.mimicCert
.get())
289 aTime
= X509_get_notAfter(properties
.mimicCert
.get());
290 if (!aTime
&& properties
.signWithX509
.get())
291 aTime
= X509_get_notAfter(properties
.signWithX509
.get());
293 if (!X509_set_notAfter(cert
.get(), aTime
))
295 } else if (!X509_gmtime_adj(X509_get_notAfter(cert
.get()), 60*60*24*356*3))
298 // mimic the alias and possibly subjectAltName
299 if (properties
.mimicCert
.get()) {
300 unsigned char *alStr
;
302 alStr
= X509_alias_get0(properties
.mimicCert
.get(), &alLen
);
304 X509_alias_set1(cert
.get(), alStr
, alLen
);
307 // Mimic subjectAltName unless we used a configured CN: browsers reject
308 // certificates with CN unrelated to subjectAltNames.
309 if (!properties
.setCommonName
) {
310 int pos
=X509_get_ext_by_NID (properties
.mimicCert
.get(), OBJ_sn2nid("subjectAltName"), -1);
311 X509_EXTENSION
*ext
=X509_get_ext(properties
.mimicCert
.get(), pos
);
313 X509_add_ext(cert
.get(), ext
, -1);
320 static bool generateFakeSslCertificate(Ssl::X509_Pointer
& certToStore
, Ssl::EVP_PKEY_Pointer
& pkeyToStore
, Ssl::CertificateProperties
const &properties
, Ssl::BIGNUM_Pointer
const &serial
)
322 Ssl::EVP_PKEY_Pointer pkey
;
323 // Use signing certificates private key as generated certificate private key
324 if (properties
.signWithPkey
.get())
325 pkey
.resetAndLock(properties
.signWithPkey
.get());
326 else // if not exist generate one
327 pkey
.reset(Ssl::createSslPrivateKey());
332 Ssl::X509_Pointer
cert(X509_new());
336 // Set pub key and serial given by the caller
337 if (!X509_set_pubkey(cert
.get(), pkey
.get()))
339 if (!setSerialNumber(X509_get_serialNumber(cert
.get()), serial
.get()))
342 // Fill the certificate with the required properties
343 if (!buildCertificate(cert
, properties
))
347 // Set issuer name, from CA or our subject name for self signed cert
348 if (properties
.signAlgorithm
!= Ssl::algSignSelf
&& properties
.signWithX509
.get())
349 ret
= X509_set_issuer_name(cert
.get(), X509_get_subject_name(properties
.signWithX509
.get()));
350 else // Self signed certificate, set issuer to self
351 ret
= X509_set_issuer_name(cert
.get(), X509_get_subject_name(cert
.get()));
355 /*Now sign the request */
356 if (properties
.signAlgorithm
!= Ssl::algSignSelf
&& properties
.signWithPkey
.get())
357 ret
= X509_sign(cert
.get(), properties
.signWithPkey
.get(), EVP_sha1());
358 else //else sign with self key (self signed request)
359 ret
= X509_sign(cert
.get(), pkey
.get(), EVP_sha1());
364 certToStore
.reset(cert
.release());
365 pkeyToStore
.reset(pkey
.release());
369 static BIGNUM
*createCertSerial(unsigned char *md
, unsigned int n
)
372 assert(n
== 20); //for sha1 n is 20 (for md5 n is 16)
374 BIGNUM
*serial
= NULL
;
375 serial
= BN_bin2bn(md
, n
, NULL
);
377 // if the serial is "0" set it to '1'
378 if (BN_is_zero(serial
))
381 // serial size does not exceed 20 bytes
382 assert(BN_num_bits(serial
) <= 160);
384 // According the RFC 5280, serial is an 20 bytes ASN.1 INTEGER (a signed big integer)
385 // and the maximum value for X.509 certificate serial number is 2^159-1 and
386 // the minimum 0. If the first bit of the serial is '1' ( eg 2^160-1),
387 // will result to a negative integer.
388 // To handle this, if the produced serial is greater than 2^159-1
389 // truncate the last bit
390 if (BN_is_bit_set(serial
, 159))
391 BN_clear_bit(serial
, 159);
396 /// Return the SHA1 digest of the DER encoded version of the certificate
397 /// stored in a BIGNUM
398 static BIGNUM
*x509Digest(Ssl::X509_Pointer
const & cert
)
401 unsigned char md
[EVP_MAX_MD_SIZE
];
403 if (!X509_digest(cert
.get(),EVP_sha1(),md
,&n
))
406 return createCertSerial(md
, n
);
409 static BIGNUM
*x509Pubkeydigest(Ssl::X509_Pointer
const & cert
)
412 unsigned char md
[EVP_MAX_MD_SIZE
];
414 if (!X509_pubkey_digest(cert
.get(),EVP_sha1(),md
,&n
))
417 return createCertSerial(md
, n
);
420 /// Generate a unique serial number based on a Ssl::CertificateProperties object
421 /// for a new generated certificate
422 static bool createSerial(Ssl::BIGNUM_Pointer
&serial
, Ssl::CertificateProperties
const &properties
)
424 Ssl::EVP_PKEY_Pointer fakePkey
;
425 Ssl::X509_Pointer fakeCert
;
427 serial
.reset(x509Pubkeydigest(properties
.signWithX509
));
429 serial
.reset(BN_new());
430 BN_is_zero(serial
.get());
433 if (!generateFakeSslCertificate(fakeCert
, fakePkey
, properties
, serial
))
436 // The x509Fingerprint return an SHA1 hash.
437 // both SHA1 hash and maximum serial number size are 20 bytes.
438 BIGNUM
*r
= x509Digest(fakeCert
);
446 bool Ssl::generateSslCertificate(Ssl::X509_Pointer
& certToStore
, Ssl::EVP_PKEY_Pointer
& pkeyToStore
, Ssl::CertificateProperties
const &properties
)
448 Ssl::BIGNUM_Pointer serial
;
450 if (!createSerial(serial
, properties
))
453 return generateFakeSslCertificate(certToStore
, pkeyToStore
, properties
, serial
);
457 \ingroup ServerProtocolSSLInternal
458 * Read certificate from file.
460 static X509
* readSslX509Certificate(char const * certFilename
)
464 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_file_internal()));
467 if (!BIO_read_filename(bio
.get(), certFilename
))
469 X509
*certificate
= PEM_read_bio_X509(bio
.get(), NULL
, NULL
, NULL
);
473 EVP_PKEY
* Ssl::readSslPrivateKey(char const * keyFilename
, pem_password_cb
*passwd_callback
)
477 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_file_internal()));
480 if (!BIO_read_filename(bio
.get(), keyFilename
))
482 EVP_PKEY
*pkey
= PEM_read_bio_PrivateKey(bio
.get(), NULL
, passwd_callback
, NULL
);
486 void Ssl::readCertAndPrivateKeyFromFiles(Ssl::X509_Pointer
& cert
, Ssl::EVP_PKEY_Pointer
& pkey
, char const * certFilename
, char const * keyFilename
)
488 if (keyFilename
== NULL
)
489 keyFilename
= certFilename
;
490 pkey
.reset(readSslPrivateKey(keyFilename
));
491 cert
.reset(readSslX509Certificate(certFilename
));
492 if (!pkey
|| !cert
|| !X509_check_private_key(cert
.get(), pkey
.get())) {
498 bool Ssl::sslDateIsInTheFuture(char const * date
)
503 tm
.data
= (unsigned char *)date
;
504 tm
.length
= strlen(date
);
506 return (X509_cmp_current_time(&tm
) > 0);
509 /// Print the time represented by a ASN1_TIME struct to a string using GeneralizedTime format
510 static bool asn1timeToGeneralizedTimeStr(ASN1_TIME
*aTime
, char *buf
, int bufLen
)
512 // ASN1_Time holds time to UTCTime or GeneralizedTime form.
513 // UTCTime has the form YYMMDDHHMMSS[Z | [+|-]offset]
514 // GeneralizedTime has the form YYYYMMDDHHMMSS[Z | [+|-] offset]
516 // length should have space for data plus 2 extra bytes for the two extra year fields
517 // plus the '\0' char.
518 if ((aTime
->length
+ 3) > bufLen
)
522 if (aTime
->type
== V_ASN1_UTCTIME
) {
523 if (aTime
->data
[0] > '5') { // RFC 2459, section 4.1.2.5.1
532 else // if (aTime->type == V_ASN1_GENERALIZEDTIME)
535 memcpy(str
, aTime
->data
, aTime
->length
);
536 str
[aTime
->length
] = '\0';
540 static int asn1time_cmp(ASN1_TIME
*asnTime1
, ASN1_TIME
*asnTime2
)
542 char strTime1
[64], strTime2
[64];
543 if (!asn1timeToGeneralizedTimeStr(asnTime1
, strTime1
, sizeof(strTime1
)))
545 if (!asn1timeToGeneralizedTimeStr(asnTime2
, strTime2
, sizeof(strTime2
)))
548 return strcmp(strTime1
, strTime2
);
551 bool Ssl::certificateMatchesProperties(X509
*cert
, CertificateProperties
const &properties
)
555 // For non self-signed certificates we have to check if the signing certificate changed
556 if (properties
.signAlgorithm
!= Ssl::algSignSelf
) {
557 assert(properties
.signWithX509
.get());
558 if (X509_check_issued(properties
.signWithX509
.get(), cert
) != X509_V_OK
)
562 X509
*cert2
= properties
.mimicCert
.get();
563 // If there is not certificate to mimic stop here
567 if (!properties
.setCommonName
) {
568 X509_NAME
*cert1_name
= X509_get_subject_name(cert
);
569 X509_NAME
*cert2_name
= X509_get_subject_name(cert2
);
570 if (X509_NAME_cmp(cert1_name
, cert2_name
) != 0)
574 if (properties.commonName != Ssl::CommonHostName(cert))
576 This function normaly called to verify a cached certificate matches the
577 specifications given by properties parameter.
578 The cached certificate retrieved from the cache using a key which has
579 as part the properties.commonName. This is enough to assume that the
580 cached cert has in its subject the properties.commonName as cn field.
584 if (!properties
.setValidBefore
) {
585 ASN1_TIME
*aTime
= X509_get_notBefore(cert
);
586 ASN1_TIME
*bTime
= X509_get_notBefore(cert2
);
587 if (asn1time_cmp(aTime
, bTime
) != 0)
591 if (!properties
.setValidAfter
) {
592 ASN1_TIME
*aTime
= X509_get_notAfter(cert
);
593 ASN1_TIME
*bTime
= X509_get_notAfter(cert2
);
594 if (asn1time_cmp(aTime
, bTime
) != 0)
600 alStr1
= (char *)X509_alias_get0(cert
, &alLen
);
601 char *alStr2
= (char *)X509_alias_get0(cert2
, &alLen
);
602 if ((!alStr1
&& alStr2
) || (alStr1
&& !alStr2
) ||
603 (alStr1
&& alStr2
&& strcmp(alStr1
, alStr2
)) != 0)
606 // Compare subjectAltName extension
607 STACK_OF(GENERAL_NAME
) * cert1_altnames
;
608 cert1_altnames
= (STACK_OF(GENERAL_NAME
)*)X509_get_ext_d2i(cert
, NID_subject_alt_name
, NULL
, NULL
);
609 STACK_OF(GENERAL_NAME
) * cert2_altnames
;
610 cert2_altnames
= (STACK_OF(GENERAL_NAME
)*)X509_get_ext_d2i(cert2
, NID_subject_alt_name
, NULL
, NULL
);
612 if (cert1_altnames
) {
613 int numalts
= sk_GENERAL_NAME_num(cert1_altnames
);
614 for (int i
= 0; match
&& i
< numalts
; i
++) {
615 const GENERAL_NAME
*aName
= sk_GENERAL_NAME_value(cert1_altnames
, i
);
616 match
= sk_GENERAL_NAME_find(cert2_altnames
, aName
);
619 else if (cert2_altnames
)
622 sk_GENERAL_NAME_pop_free(cert1_altnames
, GENERAL_NAME_free
);
623 sk_GENERAL_NAME_pop_free(cert2_altnames
, GENERAL_NAME_free
);