1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <IceSSL/Plugin.h>
6 #include <IceSSL/OpenSSL.h>
7 #include <IceSSL/CertificateI.h>
8 #include <IceSSL/OpenSSLUtil.h>
9 #include <IceSSL/RFC2253.h>
10
11 #include <IceUtil/Mutex.h>
12 #include <IceUtil/MutexPtrLock.h>
13
14 #include <openssl/x509v3.h>
15 #include <openssl/pem.h>
16
17 using namespace IceSSL;
18 using namespace std;
19
20 //
21 // Avoid old style cast warnings from OpenSSL macros
22 //
23 #if defined(__GNUC__)
24 # pragma GCC diagnostic ignored "-Wold-style-cast"
25 #endif
26
27 #ifdef __SUNPRO_CC
28
29 //
30 // The call to sk_GENERAL_NAME_pop_free fails to compile if we don't
31 // remove the extern "C" vs non extern "C" check with the macro below:
32 //
33
34 extern "C" typedef void (*FreeFunc)(void*);
35
36 #undef CHECKED_SK_FREE_FUNC
37 #define CHECKED_SK_FREE_FUNC(type, p) \
38 (FreeFunc) (p)
39
40 #endif
41
42 namespace
43 {
44
45 static string
convertX509NameToString(X509_name_st * name)46 convertX509NameToString(X509_name_st* name)
47 {
48 BIO* out = BIO_new(BIO_s_mem());
49 X509_NAME_print_ex(out, name, 0, XN_FLAG_RFC2253);
50 BUF_MEM* p;
51 BIO_get_mem_ptr(out, &p);
52 string result = string(p->data, p->length);
53 BIO_free(out);
54 return result;
55 }
56
57 static vector<pair<int, string> >
convertGeneralNames(GENERAL_NAMES * gens)58 convertGeneralNames(GENERAL_NAMES* gens)
59 {
60 vector<pair<int, string> > alt;
61 if (gens == 0)
62 {
63 return alt;
64 }
65 for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)
66 {
67 GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
68 pair<int, string> p;
69 p.first = gen->type;
70 switch (gen->type)
71 {
72 case GEN_EMAIL:
73 {
74 ASN1_IA5STRING* str = gen->d.rfc822Name;
75 if (str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
76 {
77 p.second = string(reinterpret_cast<const char*>(str->data), str->length);
78 }
79 break;
80 }
81 case GEN_DNS:
82 {
83 ASN1_IA5STRING* str = gen->d.dNSName;
84 if (str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
85 {
86 p.second = string(reinterpret_cast<const char*>(str->data), str->length);
87 }
88 break;
89 }
90 case GEN_DIRNAME:
91 {
92 p.second = convertX509NameToString(gen->d.directoryName);
93 break;
94 }
95 case GEN_URI:
96 {
97 ASN1_IA5STRING* str = gen->d.uniformResourceIdentifier;
98 if (str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
99 {
100 p.second = string(reinterpret_cast<const char*>(str->data), str->length);
101 }
102 break;
103 }
104 case GEN_IPADD:
105 {
106 ASN1_OCTET_STRING* addr = gen->d.iPAddress;
107 // TODO: Support IPv6 someday.
108 if (addr && addr->type == V_ASN1_OCTET_STRING && addr->data && addr->length == 4)
109 {
110 ostringstream ostr;
111 for (int j = 0; j < 4; ++j)
112 {
113 if (j > 0)
114 {
115 ostr << '.';
116 }
117 ostr << static_cast<int>(addr->data[j]);
118 }
119 p.second = ostr.str();
120 }
121 break;
122 }
123 case GEN_OTHERNAME:
124 case GEN_EDIPARTY:
125 case GEN_X400:
126 case GEN_RID:
127 {
128 //
129 // TODO: These types are not supported. If the user wants
130 // them, they have to get at the certificate data. Another
131 // alternative is to DER encode the data (as the Java
132 // certificate does).
133 //
134 break;
135 }
136 }
137 alt.push_back(p);
138 }
139 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
140 return alt;
141 }
142
143 class DistinguishedNameI : public IceSSL::DistinguishedName
144 {
145 public:
146
DistinguishedNameI(X509_name_st * name)147 DistinguishedNameI(X509_name_st* name) :
148 IceSSL::DistinguishedName(IceSSL::RFC2253::parseStrict(convertX509NameToString(name)))
149 {
150 unescape();
151 }
152
153 };
154
155 IceUtil::Mutex* mut = 0;
156
157 class Init
158 {
159 public:
160
Init()161 Init()
162 {
163 mut = new IceUtil::Mutex;
164 }
165
~Init()166 ~Init()
167 {
168 delete mut;
169 mut = 0;
170 }
171 };
172
173 Init init;
174
175 #ifdef ICE_CPP11_MAPPING
176 chrono::system_clock::time_point
177 #else
178 static IceUtil::Time
179 #endif
ASMUtcTimeToTime(const ASN1_UTCTIME * s)180 ASMUtcTimeToTime(const ASN1_UTCTIME* s)
181 {
182 struct tm tm;
183 int offset;
184
185 memset(&tm, '\0', sizeof tm);
186
187 # define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
188 tm.tm_year = g2(s->data);
189 if(tm.tm_year < 50)
190 {
191 tm.tm_year += 100;
192 }
193 tm.tm_mon = g2(s->data + 2) - 1;
194 tm.tm_mday = g2(s->data + 4);
195 tm.tm_hour = g2(s->data + 6);
196 tm.tm_min = g2(s->data + 8);
197 tm.tm_sec = g2(s->data + 10);
198 if(s->data[12] == 'Z')
199 {
200 offset = 0;
201 }
202 else
203 {
204 offset = g2(s->data + 13) * 60 + g2(s->data + 15);
205 if(s->data[12] == '-')
206 {
207 offset = -offset;
208 }
209 }
210 # undef g2
211
212 //
213 // If timegm was on all systems this code could be
214 // return IceUtil::Time::seconds(timegm(&tm) - offset*60);
215 //
216 // Windows doesn't support the re-entrant _r versions.
217 //
218 #if defined(_MSC_VER)
219 # pragma warning(disable:4996) // localtime is depercated
220 #endif
221 time_t tzone;
222 {
223 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mut);
224 time_t now = time(0);
225 tzone = mktime(localtime(&now)) - mktime(gmtime(&now));
226 }
227 #if defined(_MSC_VER)
228 # pragma warning(default:4996) // localtime is depercated
229 #endif
230
231 IceUtil::Time time = IceUtil::Time::seconds(mktime(&tm) - offset * 60 + tzone);
232
233 #ifdef ICE_CPP11_MAPPING
234 return chrono::system_clock::time_point(chrono::microseconds(time.toMicroSeconds()));
235 #else
236 return time;
237 #endif
238 }
239
240 class OpenSSLX509ExtensionI : public IceSSL::X509Extension
241 {
242
243 public:
244
245 OpenSSLX509ExtensionI(struct X509_extension_st*, const string&, x509_st*);
246 ~OpenSSLX509ExtensionI();
247 virtual bool isCritical() const;
248 virtual string getOID() const;
249 virtual vector<Ice::Byte> getData() const;
250
251 private:
252
253 struct X509_extension_st* _extension;
254 string _oid;
255 x509_st* _cert;
256 };
257
258 class OpenSSLCertificateI : public IceSSL::OpenSSL::Certificate,
259 public CertificateI,
260 public IceUtil::Mutex
261 {
262 public:
263
264 OpenSSLCertificateI(x509_st*);
265 ~OpenSSLCertificateI();
266
267 virtual bool operator==(const IceSSL::Certificate&) const;
268
269 virtual vector<Ice::Byte> getAuthorityKeyIdentifier() const;
270 virtual vector<Ice::Byte> getSubjectKeyIdentifier() const;
271 virtual bool verify(const IceSSL::CertificatePtr&) const;
272 virtual string encode() const;
273
274 # ifdef ICE_CPP11_MAPPING
275 virtual chrono::system_clock::time_point getNotAfter() const;
276 virtual chrono::system_clock::time_point getNotBefore() const;
277 # else
278 virtual IceUtil::Time getNotAfter() const;
279 virtual IceUtil::Time getNotBefore() const;
280 # endif
281 virtual string getSerialNumber() const;
282 virtual IceSSL::DistinguishedName getIssuerDN() const;
283 virtual vector<pair<int, string> > getIssuerAlternativeNames() const;
284 virtual IceSSL::DistinguishedName getSubjectDN() const;
285 virtual vector<pair<int, string> > getSubjectAlternativeNames() const;
286 virtual int getVersion() const;
287 virtual x509_st* getCert() const;
288
289 protected:
290
291 virtual void loadX509Extensions() const;
292
293 private:
294
295 x509_st* _cert;
296 };
297
298 } // end anonymous namespace
299
OpenSSLX509ExtensionI(struct X509_extension_st * extension,const string & oid,x509_st * cert)300 OpenSSLX509ExtensionI::OpenSSLX509ExtensionI(struct X509_extension_st* extension, const string& oid, x509_st* cert):
301 _extension(extension),
302 _oid(oid),
303 _cert(cert)
304 {
305 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
306 CRYPTO_add(&_cert->references, 1, CRYPTO_LOCK_X509);
307 #else
308 X509_up_ref(_cert);
309 #endif
310 }
311
~OpenSSLX509ExtensionI()312 OpenSSLX509ExtensionI::~OpenSSLX509ExtensionI()
313 {
314 X509_free(_cert);
315 }
316
317 bool
isCritical() const318 OpenSSLX509ExtensionI::isCritical() const
319 {
320 return X509_EXTENSION_get_critical(_extension) == 1;
321 }
322
323 string
getOID() const324 OpenSSLX509ExtensionI::getOID() const
325 {
326 return _oid;
327 }
328
329 vector<Ice::Byte>
getData() const330 OpenSSLX509ExtensionI::getData() const
331 {
332 vector<Ice::Byte> data;
333 ASN1_OCTET_STRING* buffer = X509_EXTENSION_get_data(_extension);
334 assert(buffer);
335 data.resize(buffer->length);
336 memcpy(&data[0], buffer->data, buffer->length);
337 return data;
338 }
339
340 //
341 // The caller is responsible for incrementing the reference count.
342 //
OpenSSLCertificateI(x509_st * cert)343 OpenSSLCertificateI::OpenSSLCertificateI(x509_st* cert) : _cert(cert)
344 {
345 if(!_cert)
346 {
347 #ifdef ICE_CPP11_MAPPING
348 throw invalid_argument("Invalid certificate reference");
349 #else
350 throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Invalid certificate reference");
351 #endif
352 }
353 }
354
~OpenSSLCertificateI()355 OpenSSLCertificateI::~OpenSSLCertificateI()
356 {
357 if(_cert)
358 {
359 X509_free(_cert);
360 }
361 }
362
363 bool
operator ==(const IceSSL::Certificate & r) const364 OpenSSLCertificateI::operator==(const IceSSL::Certificate& r) const
365 {
366 const OpenSSLCertificateI* p = dynamic_cast<const OpenSSLCertificateI*>(&r);
367 if(!p)
368 {
369 return false;
370 }
371
372 return X509_cmp(_cert, p->_cert) == 0;
373 }
374
375 vector<Ice::Byte>
getAuthorityKeyIdentifier() const376 OpenSSLCertificateI::getAuthorityKeyIdentifier() const
377 {
378 vector<Ice::Byte> keyid;
379 int index = X509_get_ext_by_NID(_cert, NID_authority_key_identifier, -1);
380 if(index >= 0)
381 {
382 X509_EXTENSION* ext = X509_get_ext(_cert, index);
383 if(ext)
384 {
385 AUTHORITY_KEYID* decoded = (AUTHORITY_KEYID*)X509V3_EXT_d2i(ext);
386 if(!decoded)
387 {
388 throw IceSSL::CertificateEncodingException(__FILE__, __LINE__, "the extension could not be decoded");
389 }
390 keyid.resize(decoded->keyid->length);
391 memcpy(&keyid[0], decoded->keyid->data, decoded->keyid->length);
392 AUTHORITY_KEYID_free(decoded);
393 }
394 }
395 return keyid;
396 }
397
398 vector<Ice::Byte>
getSubjectKeyIdentifier() const399 OpenSSLCertificateI::getSubjectKeyIdentifier() const
400 {
401 vector<Ice::Byte> keyid;
402 int index = X509_get_ext_by_NID(_cert, NID_subject_key_identifier, -1);
403 if(index >= 0)
404 {
405 X509_EXTENSION* ext = X509_get_ext(_cert, index);
406 if(ext)
407 {
408 ASN1_OCTET_STRING* decoded = static_cast<ASN1_OCTET_STRING*>(X509V3_EXT_d2i(ext));
409 if(!decoded)
410 {
411 throw IceSSL::CertificateEncodingException(__FILE__, __LINE__, "the extension could not be decoded");
412 }
413 keyid.resize(decoded->length);
414 memcpy(&keyid[0], decoded->data, decoded->length);
415 ASN1_OCTET_STRING_free(decoded);
416 }
417 }
418 return keyid;
419 }
420
421 bool
verify(const IceSSL::CertificatePtr & cert) const422 OpenSSLCertificateI::verify(const IceSSL::CertificatePtr& cert) const
423 {
424 OpenSSLCertificateI* c = dynamic_cast<OpenSSLCertificateI*>(cert.get());
425 if(c)
426 {
427 EVP_PKEY* key = X509_get_pubkey(c->_cert);
428 bool verified = X509_verify(_cert, key) > 0;
429 EVP_PKEY_free(key);
430 return verified;
431 }
432 return false;
433 }
434
435 string
encode() const436 OpenSSLCertificateI::encode() const
437 {
438 BIO* out = BIO_new(BIO_s_mem());
439 int i = PEM_write_bio_X509(out, _cert);
440 if(i <= 0)
441 {
442 BIO_free(out);
443 throw IceSSL::CertificateEncodingException(__FILE__, __LINE__, IceSSL::OpenSSL::getSslErrors(false));
444 }
445 BUF_MEM* p;
446 BIO_get_mem_ptr(out, &p);
447 string result = string(p->data, p->length);
448 BIO_free(out);
449 return result;
450 }
451
452 # ifdef ICE_CPP11_MAPPING
453 chrono::system_clock::time_point
454 # else
455 IceUtil::Time
456 # endif
getNotAfter() const457 OpenSSLCertificateI::getNotAfter() const
458 {
459 return ASMUtcTimeToTime(X509_get_notAfter(_cert));
460 }
461
462 # ifdef ICE_CPP11_MAPPING
463 chrono::system_clock::time_point
464 # else
465 IceUtil::Time
466 # endif
getNotBefore() const467 OpenSSLCertificateI::getNotBefore() const
468 {
469 return ASMUtcTimeToTime(X509_get_notBefore(_cert));
470 }
471
472 string
getSerialNumber() const473 OpenSSLCertificateI::getSerialNumber() const
474 {
475 BIGNUM* bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(_cert), 0);
476 char* dec = BN_bn2dec(bn);
477 string result = dec;
478 OPENSSL_free(dec);
479 BN_free(bn);
480 return result;
481 }
482
483 IceSSL::DistinguishedName
getIssuerDN() const484 OpenSSLCertificateI::getIssuerDN() const
485 {
486 return IceSSL::DistinguishedName(IceSSL::RFC2253::parseStrict(convertX509NameToString(X509_get_issuer_name(_cert))));
487 }
488
489 vector<pair<int, string> >
getIssuerAlternativeNames() const490 OpenSSLCertificateI::getIssuerAlternativeNames() const
491 {
492 return convertGeneralNames(reinterpret_cast<GENERAL_NAMES*>(X509_get_ext_d2i(_cert, NID_issuer_alt_name, 0, 0)));
493 }
494
495 IceSSL::DistinguishedName
getSubjectDN() const496 OpenSSLCertificateI::getSubjectDN() const
497 {
498 return IceSSL::DistinguishedName(IceSSL::RFC2253::parseStrict(convertX509NameToString(X509_get_subject_name(_cert))));
499 }
500
501 vector<pair<int, string> >
getSubjectAlternativeNames() const502 OpenSSLCertificateI::getSubjectAlternativeNames() const
503 {
504 return convertGeneralNames(reinterpret_cast<GENERAL_NAMES*>(X509_get_ext_d2i(_cert, NID_subject_alt_name, 0, 0)));
505 }
506
507 int
getVersion() const508 OpenSSLCertificateI::getVersion() const
509 {
510 return static_cast<int>(X509_get_version(_cert));
511 }
512
513 x509_st*
getCert() const514 OpenSSLCertificateI::getCert() const
515 {
516 return _cert;
517 }
518
519 void
loadX509Extensions() const520 OpenSSLCertificateI::loadX509Extensions() const
521 {
522 IceUtil::Mutex::Lock sync(*this);
523 if(_extensions.empty())
524 {
525 int sz = X509_get_ext_count(_cert);
526 for(int i = 0; i < sz; i++)
527 {
528 X509_EXTENSION* ext = X509_get_ext(_cert, i);
529 ASN1_OBJECT* obj = X509_EXTENSION_get_object(ext);
530 string oid;
531 //
532 // According to OBJ_obj2txt doc a buffer of length 80 should be more than enough to
533 // handle any OID encountered in practice.
534 //
535 int len = 80;
536 oid.resize(len);
537 len = OBJ_obj2txt(&oid[0], len, obj, 1);
538 oid.resize(len);
539 _extensions.push_back(ICE_DYNAMIC_CAST(IceSSL::X509Extension,
540 ICE_MAKE_SHARED(OpenSSLX509ExtensionI, ext, oid, _cert)));
541 }
542 }
543 }
544
545 IceSSL::OpenSSL::CertificatePtr
create(x509_st * cert)546 IceSSL::OpenSSL::Certificate::create(x509_st* cert)
547 {
548 return ICE_MAKE_SHARED(OpenSSLCertificateI, cert);
549 }
550
551 IceSSL::OpenSSL::CertificatePtr
load(const std::string & file)552 IceSSL::OpenSSL::Certificate::load(const std::string& file)
553 {
554 BIO* cert = BIO_new(BIO_s_file());
555 if(BIO_read_filename(cert, file.c_str()) <= 0)
556 {
557 BIO_free(cert);
558 throw CertificateReadException(__FILE__, __LINE__, "error opening file");
559 }
560
561 x509_st* x = PEM_read_bio_X509(cert, ICE_NULLPTR, ICE_NULLPTR, ICE_NULLPTR);
562 if(x == ICE_NULLPTR)
563 {
564 BIO_free(cert);
565 throw CertificateReadException(__FILE__, __LINE__, "error reading file:\n" + getSslErrors(false));
566 }
567 BIO_free(cert);
568 return ICE_MAKE_SHARED(OpenSSLCertificateI, x);
569 }
570
571 IceSSL::OpenSSL::CertificatePtr
decode(const std::string & encoding)572 IceSSL::OpenSSL::Certificate::decode(const std::string& encoding)
573 {
574 BIO *cert = BIO_new_mem_buf(static_cast<void*>(const_cast<char*>(&encoding[0])), static_cast<int>(encoding.size()));
575 x509_st* x = PEM_read_bio_X509(cert, ICE_NULLPTR, ICE_NULLPTR, ICE_NULLPTR);
576 if(x == ICE_NULLPTR)
577 {
578 BIO_free(cert);
579 throw CertificateEncodingException(__FILE__, __LINE__, getSslErrors(false));
580 }
581 BIO_free(cert);
582 return ICE_MAKE_SHARED(OpenSSLCertificateI, x);
583 }
584