ICE 3.4.2
[php5-ice-freebsdport.git] / cpp / src / IceSSL / Certificate.cpp
blob731cbd72e1a2b45c2ae08e22d9ed23deec9ab7b9
1 // **********************************************************************
2 //
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
4 //
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
7 //
8 // **********************************************************************
10 #include <IceUtil/DisableWarnings.h>
11 #include <IceUtil/Mutex.h>
12 #include <IceUtil/MutexPtrLock.h>
13 #include <IceUtil/StringUtil.h>
14 #include <IceSSL/Plugin.h>
15 #include <IceSSL/Util.h>
16 #include <IceSSL/RFC2253.h>
18 #include <openssl/x509v3.h>
19 #include <openssl/pem.h>
21 using namespace std;
22 using namespace Ice;
23 using namespace IceSSL;
25 const char* IceSSL::CertificateReadException::_name = "IceSSL::CertificateReadException";
27 CertificateReadException::CertificateReadException(const char* file, int line, const string& r) :
28 Exception(file, line),
29 reason(r)
33 CertificateReadException::~CertificateReadException() throw()
37 string
38 CertificateReadException::ice_name() const
40 return _name;
43 Exception*
44 CertificateReadException::ice_clone() const
46 return new CertificateReadException(*this);
49 void
50 CertificateReadException::ice_throw() const
52 throw *this;
55 const char* IceSSL::CertificateEncodingException::_name = "IceSSL::CertificateEncodingException";
57 CertificateEncodingException::CertificateEncodingException(const char* file, int line, const string& r) :
58 Exception(file, line),
59 reason(r)
63 CertificateEncodingException::~CertificateEncodingException() throw()
67 string
68 CertificateEncodingException::ice_name() const
70 return _name;
73 Exception*
74 CertificateEncodingException::ice_clone() const
76 return new CertificateEncodingException(*this);
79 void
80 CertificateEncodingException::ice_throw() const
82 throw *this;
85 namespace
88 IceUtil::Mutex* mut = 0;
90 class Init
92 public:
94 Init()
96 mut = new IceUtil::Mutex;
99 ~Init()
101 delete mut;
102 mut = 0;
106 Init init;
110 static IceUtil::Time
111 ASMUtcTimeToIceUtilTime(const ASN1_UTCTIME* s)
113 struct tm tm;
114 int offset;
116 memset(&tm, '\0', sizeof tm);
118 #define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
119 tm.tm_year = g2(s->data);
120 if(tm.tm_year < 50)
121 tm.tm_year += 100;
122 tm.tm_mon = g2(s->data + 2) - 1;
123 tm.tm_mday = g2(s->data + 4);
124 tm.tm_hour = g2(s->data + 6);
125 tm.tm_min = g2(s->data + 8);
126 tm.tm_sec = g2(s->data + 10);
127 if(s->data[12] == 'Z')
129 offset = 0;
131 else
133 offset = g2(s->data + 13) * 60 + g2(s->data + 15);
134 if(s->data[12] == '-')
136 offset = -offset;
139 #undef g2
142 // If timegm was on all systems this code could be
143 // return IceUtil::Time::seconds(timegm(&tm) - offset*60);
145 // Windows doesn't support the re-entrant _r versions.
147 time_t tzone;
149 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mut);
150 time_t now = time(0);
151 tzone = mktime(localtime(&now)) - mktime(gmtime(&now));
153 return IceUtil::Time::seconds(mktime(&tm) - offset*60 + tzone);
156 static string
157 convertX509NameToString(X509NAME* name)
159 BIO* out = BIO_new(BIO_s_mem());
160 X509_NAME_print_ex(out, name, 0, XN_FLAG_RFC2253);
161 BUF_MEM* p;
162 BIO_get_mem_ptr(out, &p);
163 string result = string(p->data, p->length);
164 BIO_free(out);
165 return result;
168 static vector<pair<int, string> >
169 convertGeneralNames(GENERAL_NAMES* gens)
171 vector<pair<int, string> > alt;
172 if(gens == 0)
174 return alt;
176 for(int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)
178 GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
179 pair<int, string> p;
180 p.first = gen->type;
181 switch(gen->type)
183 case GEN_EMAIL:
185 ASN1_IA5STRING* str = gen->d.rfc822Name;
186 if(str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
188 p.second = string(reinterpret_cast<const char*>(str->data), str->length);
190 break;
192 case GEN_DNS:
194 ASN1_IA5STRING* str = gen->d.dNSName;
195 if(str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
197 p.second = string(reinterpret_cast<const char*>(str->data), str->length);
199 break;
201 case GEN_DIRNAME:
203 p.second = convertX509NameToString(gen->d.directoryName);
204 break;
206 case GEN_URI:
208 ASN1_IA5STRING* str = gen->d.uniformResourceIdentifier;
209 if(str && str->type == V_ASN1_IA5STRING && str->data && str->length > 0)
211 p.second = string(reinterpret_cast<const char*>(str->data), str->length);
213 break;
215 case GEN_IPADD:
217 ASN1_OCTET_STRING* addr = gen->d.iPAddress;
218 // TODO: Support IPv6 someday.
219 if(addr && addr->type == V_ASN1_OCTET_STRING && addr->data && addr->length == 4)
221 ostringstream ostr;
222 for(int j = 0; j < 4; ++j)
224 if(j > 0)
226 ostr << '.';
228 ostr << static_cast<int>(addr->data[j]);
230 p.second = ostr.str();
232 break;
234 case GEN_OTHERNAME:
235 case GEN_EDIPARTY:
236 case GEN_X400:
237 case GEN_RID:
240 // TODO: These types are not supported. If the user wants
241 // them, they have to get at the certificate data. Another
242 // alternative is to DER encode the data (as the Java
243 // certificate does).
245 break;
248 alt.push_back(p);
250 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
251 return alt;
254 const char* ParseException::_name = "IceSSL::ParseException";
256 ParseException::ParseException(const char* file, int line, const string& r) :
257 Exception(file, line),
258 reason(r)
262 ParseException::~ParseException() throw()
266 string
267 ParseException::ice_name() const
269 return _name;
272 IceUtil::Exception*
273 ParseException::ice_clone() const
275 return new ParseException(*this);
278 void
279 ParseException::ice_throw() const
281 throw *this;
284 DistinguishedName::DistinguishedName(X509NAME* name) :
285 _rdns(RFC2253::parseStrict(convertX509NameToString(name)))
287 unescape();
290 DistinguishedName::DistinguishedName(const string& dn) :
291 _rdns(RFC2253::parseStrict(dn))
293 unescape();
296 DistinguishedName::DistinguishedName(const list<pair<string, string> >& rdns) :
297 _rdns(rdns)
299 unescape();
302 bool
303 DistinguishedName::operator==(const DistinguishedName& other) const
305 return other._unescaped == _unescaped;
308 bool
309 DistinguishedName::operator!=(const DistinguishedName& other) const
311 return other._unescaped != _unescaped;
314 bool
315 DistinguishedName::operator<(const DistinguishedName& other) const
317 return other._unescaped < _unescaped;
320 bool
321 DistinguishedName::match(const DistinguishedName& other) const
323 for(list< pair<string, string> >::const_iterator p = other._unescaped.begin(); p != other._unescaped.end(); ++p)
325 bool found = false;
326 for(list< pair<string, string> >::const_iterator q = _unescaped.begin(); q != _unescaped.end(); ++q)
328 if(p->first == q->first)
330 found = true;
331 if(p->second != q->second)
333 return false;
337 if(!found)
339 return false;
342 return true;
346 // This always produces the same output as the input DN -- the type of
347 // escaping is not changed.
349 DistinguishedName::operator string() const
351 ostringstream os;
352 bool first = true;
353 for(list< pair<string, string> >::const_iterator p = _rdns.begin(); p != _rdns.end(); ++p)
355 if(!first)
357 os << ",";
359 first = false;
360 os << p->first << "=" << p->second;
362 return os.str();
365 void
366 DistinguishedName::unescape()
368 for(list< pair<string, string> >::const_iterator q = _rdns.begin(); q != _rdns.end(); ++q)
370 pair<string, string> rdn = *q;
371 rdn.second = RFC2253::unescape(rdn.second);
372 _unescaped.push_back(rdn);
376 PublicKey::PublicKey(EVP_PKEY* key) :
377 _key(key)
381 PublicKey::~PublicKey()
383 EVP_PKEY_free(_key);
386 EVP_PKEY*
387 PublicKey::key() const
389 return _key;
393 // The caller is responsible for incrementing the reference count.
395 Certificate::Certificate(X509* cert) :
396 _cert(cert)
398 assert(_cert != 0);
401 Certificate::~Certificate()
403 X509_free(_cert);
406 CertificatePtr
407 Certificate::load(const string& file)
409 BIO *cert = BIO_new(BIO_s_file());
410 if(BIO_read_filename(cert, file.c_str()) <= 0)
412 BIO_free(cert);
413 throw CertificateReadException(__FILE__, __LINE__, "error opening file");
416 X509* x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
417 if(x == NULL)
419 BIO_free(cert);
420 throw CertificateReadException(__FILE__, __LINE__, "error reading file:\n" + getSslErrors(false));
422 BIO_free(cert);
423 return new Certificate(x);
426 CertificatePtr
427 Certificate::decode(const string& encoding)
429 BIO *cert = BIO_new_mem_buf(static_cast<void*>(const_cast<char*>(&encoding[0])), static_cast<int>(encoding.size()));
430 X509* x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
431 if(x == NULL)
433 BIO_free(cert);
434 throw CertificateReadException(__FILE__, __LINE__, "error decoding certificate:\n" + getSslErrors(false));
436 BIO_free(cert);
437 return new Certificate(x);
440 bool
441 Certificate::operator==(const Certificate& other) const
443 return X509_cmp(_cert, other._cert) == 0;
446 bool
447 Certificate::operator!=(const Certificate& other) const
449 return X509_cmp(_cert, other._cert) != 0;
452 PublicKeyPtr
453 Certificate::getPublicKey() const
455 return new PublicKey(X509_get_pubkey(_cert));
458 bool
459 Certificate::verify(const PublicKeyPtr& key) const
461 return X509_verify(_cert, key->key()) > 0;
464 string
465 Certificate::encode() const
467 BIO* out = BIO_new(BIO_s_mem());
468 int i = PEM_write_bio_X509_AUX(out, _cert);
469 if(i <= 0)
471 BIO_free(out);
472 throw CertificateEncodingException(__FILE__, __LINE__, getSslErrors(false));
474 BUF_MEM* p;
475 BIO_get_mem_ptr(out, &p);
476 string result = string(p->data, p->length);
477 BIO_free(out);
478 return result;
481 bool
482 Certificate::checkValidity() const
484 IceUtil::Time now = IceUtil::Time::now();
485 return now > getNotBefore() && now <= getNotAfter();
488 bool
489 Certificate::checkValidity(const IceUtil::Time& now) const
491 return now > getNotBefore() && now <= getNotAfter();
494 IceUtil::Time
495 Certificate::getNotAfter() const
497 return ASMUtcTimeToIceUtilTime(X509_get_notAfter(_cert));
500 IceUtil::Time
501 Certificate::getNotBefore() const
503 return ASMUtcTimeToIceUtilTime(X509_get_notBefore(_cert));
506 string
507 Certificate::getSerialNumber() const
509 BIGNUM* bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(_cert), 0);
510 char* dec = BN_bn2dec(bn);
511 string result = dec;
512 OPENSSL_free(dec);
513 BN_free(bn);
515 return result;
518 //string
519 //Certificate::getSigAlgName() const
523 //string
524 //Certificate::getSigAlgOID() const
528 DistinguishedName
529 Certificate::getIssuerDN() const
531 return DistinguishedName(X509_get_issuer_name(_cert));
534 vector<pair<int, string> >
535 Certificate::getIssuerAlternativeNames()
537 return convertGeneralNames(reinterpret_cast<GENERAL_NAMES*>(
538 X509_get_ext_d2i(_cert, NID_issuer_alt_name, 0, 0)));
541 DistinguishedName
542 Certificate::getSubjectDN() const
544 return DistinguishedName(X509_get_subject_name(_cert));
547 vector<pair<int, string> >
548 Certificate::getSubjectAlternativeNames()
550 return convertGeneralNames(
551 reinterpret_cast<GENERAL_NAMES*>(X509_get_ext_d2i(_cert, NID_subject_alt_name, 0, 0)));
555 Certificate::getVersion() const
557 return static_cast<int>(X509_get_version(_cert));
560 string
561 Certificate::toString() const
563 ostringstream os;
564 os << "serial: " << getSerialNumber() << "\n";
565 os << "issuer: " << string(getIssuerDN()) << "\n";
566 os << "subject: " << string(getSubjectDN()) << "\n";
567 os << "notBefore: " << getNotBefore().toDateTime() << "\n";
568 os << "notAfter: " << getNotAfter().toDateTime();
570 return os.str();
573 X509*
574 Certificate::getCert() const
576 return _cert;