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