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