]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/gadgets.cc
6 #include "ssl/gadgets.h"
7 #if HAVE_OPENSSL_X509V3_H
8 #include <openssl/x509v3.h>
12 \ingroup ServerProtocolSSLInternal
13 * Add CN to subject in request.
15 static bool addCnToRequest(Ssl::X509_REQ_Pointer
& request
, char const * cn
)
17 // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
18 // returns a pointer to the existing subject name. Nothing to clean here.
19 X509_NAME
*name
= X509_REQ_get_subject_name(request
.get());
23 // The second argument of the X509_NAME_add_entry_by_txt declared as
24 // "char *" on some OS. Use cn_name to avoid compile warnings.
25 static char cn_name
[3] = "CN";
26 if (!X509_NAME_add_entry_by_txt(name
, cn_name
, MBSTRING_ASC
, (unsigned char *)cn
, -1, -1, 0))
33 \ingroup ServerProtocolSSLInternal
34 * Make request on sign using private key and hostname.
36 static bool makeRequest(Ssl::X509_REQ_Pointer
& request
, Ssl::EVP_PKEY_Pointer
const & pkey
, char const * host
)
38 if (!X509_REQ_set_version(request
.get(), 0L))
41 if (!addCnToRequest(request
, host
))
44 if (!X509_REQ_set_pubkey(request
.get(), pkey
.get()))
49 EVP_PKEY
* Ssl::createSslPrivateKey()
51 Ssl::EVP_PKEY_Pointer
pkey(EVP_PKEY_new());
56 Ssl::RSA_Pointer
rsa(RSA_generate_key(1024, RSA_F4
, NULL
, NULL
));
61 if (!EVP_PKEY_assign_RSA(pkey
.get(), (rsa
.get())))
65 return pkey
.release();
68 X509_REQ
* Ssl::createNewX509Request(Ssl::EVP_PKEY_Pointer
const & pkey
, const char * hostname
)
70 Ssl::X509_REQ_Pointer
request(X509_REQ_new());
75 if (!makeRequest(request
, pkey
, hostname
))
77 return request
.release();
81 \ingroup ServerProtocolSSLInternal
82 * Set serial random serial number or set random serial number.
84 static bool setSerialNumber(ASN1_INTEGER
*ai
, BIGNUM
const* serial
)
88 Ssl::BIGNUM_Pointer
bn(BN_new());
90 bn
.reset(BN_dup(serial
));
95 if (!BN_pseudo_rand(bn
.get(), 64, 0, 0))
99 if (ai
&& !BN_to_ASN1_INTEGER(bn
.get(), ai
))
104 X509
* Ssl::signRequest(Ssl::X509_REQ_Pointer
const & request
, Ssl::X509_Pointer
const & x509
, Ssl::EVP_PKEY_Pointer
const & pkey
, ASN1_TIME
* timeNotAfter
, BIGNUM
const * serial
)
106 Ssl::X509_Pointer
cert(X509_new());
110 if (!setSerialNumber(X509_get_serialNumber(cert
.get()), serial
))
113 if (!X509_set_issuer_name(cert
.get(), x509
.get() ? X509_get_subject_name(x509
.get()) : X509_REQ_get_subject_name(request
.get())))
116 if (!X509_gmtime_adj(X509_get_notBefore(cert
.get()), (-2)*24*60*60))
120 if (!X509_set_notAfter(cert
.get(), timeNotAfter
))
122 } else if (!X509_gmtime_adj(X509_get_notAfter(cert
.get()), 60*60*24*356*3))
125 if (!X509_set_subject_name(cert
.get(), X509_REQ_get_subject_name(request
.get())))
128 Ssl::EVP_PKEY_Pointer
tmppkey(X509_REQ_get_pubkey(request
.get()));
130 if (!tmppkey
|| !X509_set_pubkey(cert
.get(), tmppkey
.get()))
133 if (!X509_sign(cert
.get(), pkey
.get(), EVP_sha1()))
136 return cert
.release();
139 bool Ssl::writeCertAndPrivateKeyToMemory(Ssl::X509_Pointer
const & cert
, Ssl::EVP_PKEY_Pointer
const & pkey
, std::string
& bufferToWrite
)
141 bufferToWrite
.clear();
144 BIO_Pointer
bio(BIO_new(BIO_s_mem()));
148 if (!PEM_write_bio_X509 (bio
.get(), cert
.get()))
151 if (!PEM_write_bio_PrivateKey(bio
.get(), pkey
.get(), NULL
, NULL
, 0, NULL
, NULL
))
155 long len
= BIO_get_mem_data(bio
.get(), &ptr
);
159 bufferToWrite
= std::string(ptr
, len
);
163 bool Ssl::appendCertToMemory(Ssl::X509_Pointer
const & cert
, std::string
& bufferToWrite
)
168 BIO_Pointer
bio(BIO_new(BIO_s_mem()));
172 if (!PEM_write_bio_X509 (bio
.get(), cert
.get()))
176 long len
= BIO_get_mem_data(bio
.get(), &ptr
);
180 if (!bufferToWrite
.empty())
181 bufferToWrite
.append(" "); // add a space...
183 bufferToWrite
.append(ptr
, len
);
187 bool Ssl::writeCertAndPrivateKeyToFile(Ssl::X509_Pointer
const & cert
, Ssl::EVP_PKEY_Pointer
const & pkey
, char const * filename
)
192 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_file_internal()));
195 if (!BIO_write_filename(bio
.get(), const_cast<char *>(filename
)))
198 if (!PEM_write_bio_X509(bio
.get(), cert
.get()))
201 if (!PEM_write_bio_PrivateKey(bio
.get(), pkey
.get(), NULL
, NULL
, 0, NULL
, NULL
))
207 bool Ssl::readCertAndPrivateKeyFromMemory(Ssl::X509_Pointer
& cert
, Ssl::EVP_PKEY_Pointer
& pkey
, char const * bufferToRead
)
209 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_mem()));
210 BIO_puts(bio
.get(), bufferToRead
);
212 X509
* certPtr
= NULL
;
213 cert
.reset(PEM_read_bio_X509(bio
.get(), &certPtr
, 0, 0));
217 EVP_PKEY
* pkeyPtr
= NULL
;
218 pkey
.reset(PEM_read_bio_PrivateKey(bio
.get(), &pkeyPtr
, 0, 0));
225 bool Ssl::readCertFromMemory(X509_Pointer
& cert
, char const * bufferToRead
)
227 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_mem()));
228 BIO_puts(bio
.get(), bufferToRead
);
230 X509
* certPtr
= NULL
;
231 cert
.reset(PEM_read_bio_X509(bio
.get(), &certPtr
, 0, 0));
238 bool Ssl::generateSslCertificateAndPrivateKey(char const *host
, Ssl::X509_Pointer
const & signedX509
, Ssl::EVP_PKEY_Pointer
const & signedPkey
, Ssl::X509_Pointer
& cert
, Ssl::EVP_PKEY_Pointer
& pkey
, BIGNUM
const * serial
)
240 pkey
.reset(createSslPrivateKey());
244 Ssl::X509_REQ_Pointer
request(createNewX509Request(pkey
, host
));
248 if (signedX509
.get() && signedPkey
.get())
249 cert
.reset(signRequest(request
, signedX509
, signedPkey
, X509_get_notAfter(signedX509
.get()), serial
));
251 cert
.reset(signRequest(request
, signedX509
, pkey
, NULL
, serial
));
259 static bool mimicCertificate(Ssl::X509_Pointer
& cert
, Ssl::X509_Pointer
const & caCert
, Ssl::X509_Pointer
const &certToMimic
)
261 // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
262 // returns a pointer to the existing subject name. Nothing to clean here.
263 X509_NAME
*name
= X509_get_subject_name(certToMimic
.get());
266 // X509_set_subject_name will call X509_dup for name
267 X509_set_subject_name(cert
.get(), name
);
270 // We should get caCert notBefore and notAfter fields and do not allow
271 // notBefore/notAfter values from certToMimic before/after notBefore/notAfter
272 // fields from caCert.
273 // Currently there is not any way in openssl tollkit to compare two ASN1_TIME
276 if ((aTime
= X509_get_notBefore(certToMimic
.get())) || (aTime
= X509_get_notBefore(caCert
.get())) ) {
277 if (!X509_set_notBefore(cert
.get(), aTime
))
280 else if (!X509_gmtime_adj(X509_get_notBefore(cert
.get()), (-2)*24*60*60))
283 if ((aTime
= X509_get_notAfter(certToMimic
.get())) || (aTime
= X509_get_notAfter(caCert
.get())) ) {
284 if (!X509_set_notAfter(cert
.get(), aTime
))
286 } else if (!X509_gmtime_adj(X509_get_notAfter(cert
.get()), 60*60*24*356*3))
290 unsigned char *alStr
;
292 alStr
= X509_alias_get0(certToMimic
.get(), &alLen
);
294 X509_alias_set1(cert
.get(), alStr
, alLen
);
297 // Add subjectAltName extension used to support multiple hostnames with one certificate
298 int pos
=X509_get_ext_by_NID (certToMimic
.get(), OBJ_sn2nid("subjectAltName"), -1);
299 X509_EXTENSION
*ext
=X509_get_ext(certToMimic
.get(), pos
);
301 X509_add_ext(cert
.get(), ext
, -1);
306 bool Ssl::generateSslCertificate(Ssl::X509_Pointer
const &certToMimic
, Ssl::X509_Pointer
const & signedX509
, Ssl::EVP_PKEY_Pointer
const & signedPkey
, Ssl::X509_Pointer
& certToStore
, Ssl::EVP_PKEY_Pointer
& pkey
, BIGNUM
const * serial
)
308 if (!certToMimic
.get())
311 pkey
.reset(createSslPrivateKey());
315 Ssl::X509_Pointer
cert(X509_new());
319 // Set pub key and serial given by the caller
320 if (!X509_set_pubkey(cert
.get(), pkey
.get()))
322 if (!setSerialNumber(X509_get_serialNumber(cert
.get()), serial
))
325 // inherit properties from certToMimic
326 if (!mimicCertificate(cert
, signedX509
, certToMimic
))
329 // Set issuer name, from CA or our subject name for self signed cert
330 if (!X509_set_issuer_name(cert
.get(), signedX509
.get() ? X509_get_subject_name(signedX509
.get()) : X509_get_subject_name(cert
.get())))
333 /*Now sign the request */
335 if (signedPkey
.get())
336 ret
= X509_sign(cert
.get(), signedPkey
.get(), EVP_sha1());
337 else //else sign with self key (self signed request)
338 ret
= X509_sign(cert
.get(), pkey
.get(), EVP_sha1());
343 certToStore
.reset(cert
.release());
348 \ingroup ServerProtocolSSLInternal
349 * Read certificate from file.
351 static X509
* readSslX509Certificate(char const * certFilename
)
355 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_file_internal()));
358 if (!BIO_read_filename(bio
.get(), certFilename
))
360 X509
*certificate
= PEM_read_bio_X509(bio
.get(), NULL
, NULL
, NULL
);
364 EVP_PKEY
* Ssl::readSslPrivateKey(char const * keyFilename
)
368 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_file_internal()));
371 if (!BIO_read_filename(bio
.get(), keyFilename
))
373 EVP_PKEY
*pkey
= PEM_read_bio_PrivateKey(bio
.get(), NULL
, NULL
, NULL
);
377 void Ssl::readCertAndPrivateKeyFromFiles(Ssl::X509_Pointer
& cert
, Ssl::EVP_PKEY_Pointer
& pkey
, char const * certFilename
, char const * keyFilename
)
379 if (keyFilename
== NULL
)
380 keyFilename
= certFilename
;
381 pkey
.reset(readSslPrivateKey(keyFilename
));
382 cert
.reset(readSslX509Certificate(certFilename
));
383 if (!pkey
|| !cert
|| !X509_check_private_key(cert
.get(), pkey
.get())) {
389 bool Ssl::sslDateIsInTheFuture(char const * date
)
394 tm
.data
= (unsigned char *)date
;
395 tm
.length
= strlen(date
);
397 return (X509_cmp_current_time(&tm
) > 0);