]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/gadgets.cc
Bug fix: sslpassword_program for ssl-bump http ports
[thirdparty/squid.git] / src / ssl / gadgets.cc
1 /*
2 * $Id$
3 */
4
5 #include "squid.h"
6 #include "ssl/gadgets.h"
7 #if HAVE_OPENSSL_X509V3_H
8 #include <openssl/x509v3.h>
9 #endif
10
11 /**
12 \ingroup ServerProtocolSSLInternal
13 * Add CN to subject in request.
14 */
15 static bool addCnToRequest(Ssl::X509_REQ_Pointer & request, char const * cn)
16 {
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());
20 if (!name)
21 return false;
22
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))
27 return false;
28
29 return true;
30 }
31
32 /**
33 \ingroup ServerProtocolSSLInternal
34 * Make request on sign using private key and hostname.
35 */
36 static bool makeRequest(Ssl::X509_REQ_Pointer & request, Ssl::EVP_PKEY_Pointer const & pkey, char const * host)
37 {
38 if (!X509_REQ_set_version(request.get(), 0L))
39 return false;
40
41 if (!addCnToRequest(request, host))
42 return false;
43
44 if (!X509_REQ_set_pubkey(request.get(), pkey.get()))
45 return false;
46 return true;
47 }
48
49 EVP_PKEY * Ssl::createSslPrivateKey()
50 {
51 Ssl::EVP_PKEY_Pointer pkey(EVP_PKEY_new());
52
53 if (!pkey)
54 return NULL;
55
56 Ssl::RSA_Pointer rsa(RSA_generate_key(1024, RSA_F4, NULL, NULL));
57
58 if (!rsa)
59 return NULL;
60
61 if (!EVP_PKEY_assign_RSA(pkey.get(), (rsa.get())))
62 return NULL;
63
64 rsa.release();
65 return pkey.release();
66 }
67
68 X509_REQ * Ssl::createNewX509Request(Ssl::EVP_PKEY_Pointer const & pkey, const char * hostname)
69 {
70 Ssl::X509_REQ_Pointer request(X509_REQ_new());
71
72 if (!request)
73 return NULL;
74
75 if (!makeRequest(request, pkey, hostname))
76 return NULL;
77 return request.release();
78 }
79
80 /**
81 \ingroup ServerProtocolSSLInternal
82 * Set serial random serial number or set random serial number.
83 */
84 static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const* serial)
85 {
86 if (!ai)
87 return false;
88 Ssl::BIGNUM_Pointer bn(BN_new());
89 if (serial) {
90 bn.reset(BN_dup(serial));
91 } else {
92 if (!bn)
93 return false;
94
95 if (!BN_pseudo_rand(bn.get(), 64, 0, 0))
96 return false;
97 }
98
99 if (ai && !BN_to_ASN1_INTEGER(bn.get(), ai))
100 return false;
101 return true;
102 }
103
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)
105 {
106 Ssl::X509_Pointer cert(X509_new());
107 if (!cert)
108 return NULL;
109
110 if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial))
111 return NULL;
112
113 if (!X509_set_issuer_name(cert.get(), x509.get() ? X509_get_subject_name(x509.get()) : X509_REQ_get_subject_name(request.get())))
114 return NULL;
115
116 if (!X509_gmtime_adj(X509_get_notBefore(cert.get()), (-2)*24*60*60))
117 return NULL;
118
119 if (timeNotAfter) {
120 if (!X509_set_notAfter(cert.get(), timeNotAfter))
121 return NULL;
122 } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
123 return NULL;
124
125 if (!X509_set_subject_name(cert.get(), X509_REQ_get_subject_name(request.get())))
126 return NULL;
127
128 Ssl::EVP_PKEY_Pointer tmppkey(X509_REQ_get_pubkey(request.get()));
129
130 if (!tmppkey || !X509_set_pubkey(cert.get(), tmppkey.get()))
131 return NULL;
132
133 if (!X509_sign(cert.get(), pkey.get(), EVP_sha1()))
134 return NULL;
135
136 return cert.release();
137 }
138
139 bool Ssl::writeCertAndPrivateKeyToMemory(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, std::string & bufferToWrite)
140 {
141 bufferToWrite.clear();
142 if (!pkey || !cert)
143 return false;
144 BIO_Pointer bio(BIO_new(BIO_s_mem()));
145 if (!bio)
146 return false;
147
148 if (!PEM_write_bio_X509 (bio.get(), cert.get()))
149 return false;
150
151 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
152 return false;
153
154 char *ptr = NULL;
155 long len = BIO_get_mem_data(bio.get(), &ptr);
156 if (!ptr)
157 return false;
158
159 bufferToWrite = std::string(ptr, len);
160 return true;
161 }
162
163 bool Ssl::writeCertAndPrivateKeyToFile(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, char const * filename)
164 {
165 if (!pkey || !cert)
166 return false;
167
168 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
169 if (!bio)
170 return false;
171 if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
172 return false;
173
174 if (!PEM_write_bio_X509(bio.get(), cert.get()))
175 return false;
176
177 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
178 return false;
179
180 return true;
181 }
182
183 bool Ssl::readCertAndPrivateKeyFromMemory(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * bufferToRead)
184 {
185 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
186 BIO_puts(bio.get(), bufferToRead);
187
188 X509 * certPtr = NULL;
189 cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
190 if (!cert)
191 return false;
192
193 EVP_PKEY * pkeyPtr = NULL;
194 pkey.reset(PEM_read_bio_PrivateKey(bio.get(), &pkeyPtr, 0, 0));
195 if (!pkey)
196 return false;
197
198 return true;
199 }
200
201 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)
202 {
203 pkey.reset(createSslPrivateKey());
204 if (!pkey)
205 return false;
206
207 Ssl::X509_REQ_Pointer request(createNewX509Request(pkey, host));
208 if (!request)
209 return false;
210
211 if (signedX509.get() && signedPkey.get())
212 cert.reset(signRequest(request, signedX509, signedPkey, X509_get_notAfter(signedX509.get()), serial));
213 else
214 cert.reset(signRequest(request, signedX509, pkey, NULL, serial));
215
216 if (!cert)
217 return false;
218
219 return true;
220 }
221
222 /**
223 \ingroup ServerProtocolSSLInternal
224 * Read certificate from file.
225 */
226 static X509 * readSslX509Certificate(char const * certFilename)
227 {
228 if (!certFilename)
229 return NULL;
230 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
231 if (!bio)
232 return NULL;
233 if (!BIO_read_filename(bio.get(), certFilename))
234 return NULL;
235 X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
236 return certificate;
237 }
238
239 EVP_PKEY * Ssl::readSslPrivateKey(char const * keyFilename, pem_password_cb *passwd_callback)
240 {
241 if (!keyFilename)
242 return NULL;
243 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
244 if (!bio)
245 return NULL;
246 if (!BIO_read_filename(bio.get(), keyFilename))
247 return NULL;
248 EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio.get(), NULL, passwd_callback, NULL);
249 return pkey;
250 }
251
252 void Ssl::readCertAndPrivateKeyFromFiles(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename)
253 {
254 if (keyFilename == NULL)
255 keyFilename = certFilename;
256 pkey.reset(readSslPrivateKey(keyFilename));
257 cert.reset(readSslX509Certificate(certFilename));
258 if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
259 pkey.reset(NULL);
260 cert.reset(NULL);
261 }
262 }
263
264 bool Ssl::sslDateIsInTheFuture(char const * date)
265 {
266 ASN1_UTCTIME tm;
267 tm.flags = 0;
268 tm.type = 23;
269 tm.data = (unsigned char *)date;
270 tm.length = strlen(date);
271
272 return (X509_cmp_current_time(&tm) > 0);
273 }