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