1 // **********************************************************************
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
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>
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
),
33 CertificateReadException::~CertificateReadException() throw()
38 CertificateReadException::ice_name() const
44 CertificateReadException::ice_clone() const
46 return new CertificateReadException(*this);
50 CertificateReadException::ice_throw() const
55 const char* IceSSL::CertificateEncodingException::_name
= "IceSSL::CertificateEncodingException";
57 CertificateEncodingException::CertificateEncodingException(const char* file
, int line
, const string
& r
) :
58 Exception(file
, line
),
63 CertificateEncodingException::~CertificateEncodingException() throw()
68 CertificateEncodingException::ice_name() const
74 CertificateEncodingException::ice_clone() const
76 return new CertificateEncodingException(*this);
80 CertificateEncodingException::ice_throw() const
88 IceUtil::Mutex
* mut
= 0;
96 mut
= new IceUtil::Mutex
;
111 ASMUtcTimeToIceUtilTime(const ASN1_UTCTIME
* s
)
116 memset(&tm
, '\0', sizeof tm
);
118 #define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
119 tm
.tm_year
= g2(s
->data
);
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')
133 offset
= g2(s
->data
+ 13) * 60 + g2(s
->data
+ 15);
134 if(s
->data
[12] == '-')
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.
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
);
157 convertX509NameToString(X509NAME
* name
)
159 BIO
* out
= BIO_new(BIO_s_mem());
160 X509_NAME_print_ex(out
, name
, 0, XN_FLAG_RFC2253
);
162 BIO_get_mem_ptr(out
, &p
);
163 string result
= string(p
->data
, p
->length
);
168 static vector
<pair
<int, string
> >
169 convertGeneralNames(GENERAL_NAMES
* gens
)
171 vector
<pair
<int, string
> > alt
;
176 for(int i
= 0; i
< sk_GENERAL_NAME_num(gens
); ++i
)
178 GENERAL_NAME
* gen
= sk_GENERAL_NAME_value(gens
, i
);
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
);
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
);
203 p
.second
= convertX509NameToString(gen
->d
.directoryName
);
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
);
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)
222 for(int j
= 0; j
< 4; ++j
)
228 ostr
<< static_cast<int>(addr
->data
[j
]);
230 p
.second
= ostr
.str();
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).
250 sk_GENERAL_NAME_pop_free(gens
, GENERAL_NAME_free
);
254 const char* ParseException::_name
= "IceSSL::ParseException";
256 ParseException::ParseException(const char* file
, int line
, const string
& r
) :
257 Exception(file
, line
),
262 ParseException::~ParseException() throw()
267 ParseException::ice_name() const
273 ParseException::ice_clone() const
275 return new ParseException(*this);
279 ParseException::ice_throw() const
284 DistinguishedName::DistinguishedName(X509NAME
* name
) :
285 _rdns(RFC2253::parseStrict(convertX509NameToString(name
)))
290 DistinguishedName::DistinguishedName(const string
& dn
) :
291 _rdns(RFC2253::parseStrict(dn
))
296 DistinguishedName::DistinguishedName(const list
<pair
<string
, string
> >& rdns
) :
303 DistinguishedName::operator==(const DistinguishedName
& other
) const
305 return other
._unescaped
== _unescaped
;
309 DistinguishedName::operator!=(const DistinguishedName
& other
) const
311 return other
._unescaped
!= _unescaped
;
315 DistinguishedName::operator<(const DistinguishedName
& other
) const
317 return other
._unescaped
< _unescaped
;
321 DistinguishedName::match(const DistinguishedName
& other
) const
323 for(list
< pair
<string
, string
> >::const_iterator p
= other
._unescaped
.begin(); p
!= other
._unescaped
.end(); ++p
)
326 for(list
< pair
<string
, string
> >::const_iterator q
= _unescaped
.begin(); q
!= _unescaped
.end(); ++q
)
328 if(p
->first
== q
->first
)
331 if(p
->second
!= q
->second
)
346 // This always produces the same output as the input DN -- the type of
347 // escaping is not changed.
349 DistinguishedName::operator string() const
353 for(list
< pair
<string
, string
> >::const_iterator p
= _rdns
.begin(); p
!= _rdns
.end(); ++p
)
360 os
<< p
->first
<< "=" << p
->second
;
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
) :
381 PublicKey::~PublicKey()
387 PublicKey::key() const
393 // The caller is responsible for incrementing the reference count.
395 Certificate::Certificate(X509
* cert
) :
401 Certificate::~Certificate()
407 Certificate::load(const string
& file
)
409 BIO
*cert
= BIO_new(BIO_s_file());
410 if(BIO_read_filename(cert
, file
.c_str()) <= 0)
413 throw CertificateReadException(__FILE__
, __LINE__
, "error opening file");
416 X509
* x
= PEM_read_bio_X509_AUX(cert
, NULL
, NULL
, NULL
);
420 throw CertificateReadException(__FILE__
, __LINE__
, "error reading file:\n" + getSslErrors(false));
423 return new Certificate(x
);
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
);
434 throw CertificateReadException(__FILE__
, __LINE__
, "error decoding certificate:\n" + getSslErrors(false));
437 return new Certificate(x
);
441 Certificate::operator==(const Certificate
& other
) const
443 return X509_cmp(_cert
, other
._cert
) == 0;
447 Certificate::operator!=(const Certificate
& other
) const
449 return X509_cmp(_cert
, other
._cert
) != 0;
453 Certificate::getPublicKey() const
455 return new PublicKey(X509_get_pubkey(_cert
));
459 Certificate::verify(const PublicKeyPtr
& key
) const
461 return X509_verify(_cert
, key
->key()) > 0;
465 Certificate::encode() const
467 BIO
* out
= BIO_new(BIO_s_mem());
468 int i
= PEM_write_bio_X509_AUX(out
, _cert
);
472 throw CertificateEncodingException(__FILE__
, __LINE__
, getSslErrors(false));
475 BIO_get_mem_ptr(out
, &p
);
476 string result
= string(p
->data
, p
->length
);
482 Certificate::checkValidity() const
484 IceUtil::Time now
= IceUtil::Time::now();
485 return now
> getNotBefore() && now
<= getNotAfter();
489 Certificate::checkValidity(const IceUtil::Time
& now
) const
491 return now
> getNotBefore() && now
<= getNotAfter();
495 Certificate::getNotAfter() const
497 return ASMUtcTimeToIceUtilTime(X509_get_notAfter(_cert
));
501 Certificate::getNotBefore() const
503 return ASMUtcTimeToIceUtilTime(X509_get_notBefore(_cert
));
507 Certificate::getSerialNumber() const
509 BIGNUM
* bn
= ASN1_INTEGER_to_BN(X509_get_serialNumber(_cert
), 0);
510 char* dec
= BN_bn2dec(bn
);
519 //Certificate::getSigAlgName() const
524 //Certificate::getSigAlgOID() const
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)));
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
));
561 Certificate::toString() const
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();
574 Certificate::getCert() const