2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
24 * A helper class for working with keys, certificates, etc.
29 #include "io/HTTPResponse.h"
30 #include "security/OpenSSLCryptoX509CRL.h"
31 #include "security/SecurityHelper.h"
32 #include "security/X509Credential.h"
33 #include "soap/HTTPSOAPTransport.h"
37 #include <openssl/evp.h>
38 #include <openssl/pem.h>
39 #include <openssl/pkcs12.h>
40 #include <xsec/enc/XSECCryptoException.hpp>
41 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
42 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
43 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
44 #include <xercesc/util/Base64.hpp>
47 # if (OPENSSL_VERSION_NUMBER >= 0x00907000)
48 # define XMLTOOLING_OPENSSL_HAVE_EC 1
52 #if defined(XMLTOOLING_XMLSEC_ECC) && defined(XMLTOOLING_OPENSSL_HAVE_EC)
53 # include <xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.hpp>
56 using namespace xmltooling::logging;
57 using namespace xmltooling;
60 // OpenSSL password callback...
61 static int passwd_callback(char* buf, int len, int verify, void* passwd)
65 if(passwd && len > strlen(reinterpret_cast<char*>(passwd)))
67 strcpy(buf,reinterpret_cast<char*>(passwd));
74 const char* SecurityHelper::guessEncodingFormat(const char* pathname)
76 const char* format=nullptr;
77 BIO* in=BIO_new(BIO_s_file_internal());
78 if (in && BIO_read_filename(in, pathname)>0) {
79 const int READSIZE = 1;
83 // Examine the first byte.
85 if ((mark = BIO_tell(in)) < 0)
86 throw XMLSecurityException("Error loading file: BIO_tell() can't get the file position.");
87 if (BIO_read(in, buf, READSIZE) <= 0)
88 throw XMLSecurityException("Error loading file: BIO_read() can't read from the stream.");
89 if (BIO_seek(in, mark) < 0)
90 throw XMLSecurityException("Error loading file: BIO_seek() can't reset the file position.");
98 // Check the first byte of the file. If it's some kind of DER-encoded structure
99 // (including PKCS12), it will begin with ASCII 048. Otherwise, assume it's PEM.
104 // Here we know it's DER-encoded, now try to parse it as a PKCS12 ASN.1 structure.
105 // If it fails, must be another kind of DER-encoded structure.
107 if ((p12=d2i_PKCS12_bio(in, nullptr)) == nullptr) {
120 throw XMLSecurityException("Unable to determine encoding for file ($1).", params(1,pathname));
123 XSECCryptoKey* SecurityHelper::loadKeyFromFile(const char* pathname, const char* format, const char* password)
126 NDC ndc("loadKeyFromFile");
128 Category& log = Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper");
129 log.info("loading private key from file (%s)", pathname);
133 EVP_PKEY* pkey=nullptr;
135 BIO* in=BIO_new(BIO_s_file_internal());
136 if (in && BIO_read_filename(in, pathname)>0) {
137 // If the format isn't set, try and guess it.
138 if (!format || !*format) {
139 const int READSIZE = 1;
143 // Examine the first byte.
145 if ((mark = BIO_tell(in)) < 0)
146 throw XMLSecurityException("Error loading key: BIO_tell() can't get the file position.");
147 if (BIO_read(in, buf, READSIZE) <= 0)
148 throw XMLSecurityException("Error loading key: BIO_read() can't read from the stream.");
149 if (BIO_seek(in, mark) < 0)
150 throw XMLSecurityException("Error loading key: BIO_seek() can't reset the file position.");
158 // Check the first byte of the file. If it's some kind of DER-encoded structure
159 // (including PKCS12), it will begin with ASCII 048. Otherwise, assume it's PEM.
164 // Here we know it's DER-encoded, now try to parse it as a PKCS12 ASN.1 structure.
165 // If it fails, must be another kind of DER-encoded structure.
166 if ((p12=d2i_PKCS12_bio(in, nullptr)) == nullptr) {
168 if (BIO_seek(in, mark) < 0) {
171 throw XMLSecurityException("Error loading key: BIO_seek() can't reset the file position.");
178 log.debug("key encoding format for (%s) dynamically resolved as (%s)", pathname, format);
181 // The format should be known, so parse accordingly.
182 if (!strcmp(format, "PEM")) {
183 pkey = PEM_read_bio_PrivateKey(in, nullptr, passwd_callback, const_cast<char*>(password));
185 else if (!strcmp(format, "DER")) {
186 pkey=d2i_PrivateKey_bio(in, nullptr);
188 else if (!strcmp(format, "PKCS12")) {
190 p12 = d2i_PKCS12_bio(in, nullptr);
193 PKCS12_parse(p12, const_cast<char*>(password), &pkey, &x, nullptr);
199 log.error("unknown key encoding format (%s)", format);
205 // Now map it to an XSEC wrapper.
207 XSECCryptoKey* ret=nullptr;
208 switch (pkey->type) {
210 ret=new OpenSSLCryptoKeyRSA(pkey);
214 ret=new OpenSSLCryptoKeyDSA(pkey);
217 #if defined(XMLTOOLING_XMLSEC_ECC) && defined(XMLTOOLING_OPENSSL_HAVE_EC)
219 ret=new OpenSSLCryptoKeyEC(pkey);
223 log.error("unsupported private key type");
231 throw XMLSecurityException("Unable to load private key from file ($1).", params(1, pathname));
234 vector<XSECCryptoX509*>::size_type SecurityHelper::loadCertificatesFromFile(
235 vector<XSECCryptoX509*>& certs, const char* pathname, const char* format, const char* password
239 NDC ndc("loadCertificatesFromFile");
241 Category& log = Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper");
242 log.info("loading certificate(s) from file (%s)", pathname);
244 vector<XSECCryptoX509*>::size_type count = certs.size();
250 BIO* in=BIO_new(BIO_s_file_internal());
251 if (in && BIO_read_filename(in, pathname)>0) {
252 // If the format isn't set, try and guess it.
253 if (!format || !*format) {
254 const int READSIZE = 1;
258 // Examine the first byte.
260 if ((mark = BIO_tell(in)) < 0)
261 throw XMLSecurityException("Error loading certificate: BIO_tell() can't get the file position.");
262 if (BIO_read(in, buf, READSIZE) <= 0)
263 throw XMLSecurityException("Error loading certificate: BIO_read() can't read from the stream.");
264 if (BIO_seek(in, mark) < 0)
265 throw XMLSecurityException("Error loading certificate: BIO_seek() can't reset the file position.");
273 // Check the first byte of the file. If it's some kind of DER-encoded structure
274 // (including PKCS12), it will begin with ASCII 048. Otherwise, assume it's PEM.
279 // Here we know it's DER-encoded, now try to parse it as a PKCS12 ASN.1 structure.
280 // If it fails, must be another kind of DER-encoded structure.
281 if ((p12=d2i_PKCS12_bio(in, nullptr)) == nullptr) {
283 if (BIO_seek(in, mark) < 0) {
286 throw XMLSecurityException("Error loading certificate: BIO_seek() can't reset the file position.");
295 // The format should be known, so parse accordingly.
296 if (!strcmp(format, "PEM")) {
297 while (x=PEM_read_bio_X509(in, nullptr, nullptr, nullptr)) {
298 certs.push_back(new OpenSSLCryptoX509(x));
302 else if (!strcmp(format, "DER")) {
303 x=d2i_X509_bio(in, nullptr);
305 certs.push_back(new OpenSSLCryptoX509(x));
309 else if (!strcmp(format, "PKCS12")) {
311 p12 = d2i_PKCS12_bio(in, nullptr);
313 EVP_PKEY* pkey=nullptr;
314 STACK_OF(X509)* CAstack = sk_X509_new_null();
315 PKCS12_parse(p12, const_cast<char*>(password), &pkey, &x, &CAstack);
319 certs.push_back(new OpenSSLCryptoX509(x));
322 x = sk_X509_pop(CAstack);
324 certs.push_back(new OpenSSLCryptoX509(x));
326 x = sk_X509_pop(CAstack);
328 sk_X509_free(CAstack);
335 if (certs.size() == count) {
337 throw XMLSecurityException("Unable to load certificate(s) from file ($1).", params(1, pathname));
343 vector<XSECCryptoX509CRL*>::size_type SecurityHelper::loadCRLsFromFile(
344 vector<XSECCryptoX509CRL*>& crls, const char* pathname, const char* format
348 NDC ndc("loadCRLsFromFile");
350 Category& log = Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper");
351 log.info("loading CRL(s) from file (%s)", pathname);
353 vector<XSECCryptoX509CRL*>::size_type count = crls.size();
355 BIO* in=BIO_new(BIO_s_file_internal());
356 if (in && BIO_read_filename(in, pathname)>0) {
357 // If the format isn't set, try and guess it.
358 if (!format || !*format) {
359 const int READSIZE = 1;
363 // Examine the first byte.
365 if ((mark = BIO_tell(in)) < 0)
366 throw XMLSecurityException("Error loading CRL: BIO_tell() can't get the file position.");
367 if (BIO_read(in, buf, READSIZE) <= 0)
368 throw XMLSecurityException("Error loading CRL: BIO_read() can't read from the stream.");
369 if (BIO_seek(in, mark) < 0)
370 throw XMLSecurityException("Error loading CRL: BIO_seek() can't reset the file position.");
378 // Check the first byte of the file. If it's some kind of DER-encoded structure
379 // it will begin with ASCII 048. Otherwise, assume it's PEM.
386 log.debug("CRL encoding format for (%s) dynamically resolved as (%s)", pathname, format);
389 X509_CRL* crl=nullptr;
390 if (!strcmp(format, "PEM")) {
391 while (crl=PEM_read_bio_X509_CRL(in, nullptr, nullptr, nullptr)) {
392 crls.push_back(new OpenSSLCryptoX509CRL(crl));
396 else if (!strcmp(format, "DER")) {
397 crl=d2i_X509_CRL_bio(in, nullptr);
399 crls.push_back(new OpenSSLCryptoX509CRL(crl));
404 log.error("unknown CRL encoding format (%s)", format);
410 if (crls.size() == count) {
412 throw XMLSecurityException("Unable to load CRL(s) from file ($1).", params(1, pathname));
418 XSECCryptoKey* SecurityHelper::loadKeyFromURL(SOAPTransport& transport, const char* backing, const char* format, const char* password)
422 istream& msg = transport.receive();
424 // Check for "not modified" status.
425 if (dynamic_cast<HTTPSOAPTransport*>(&transport) && transport.getStatusCode() == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)
426 throw (long)HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED;
428 // Dump to output file.
429 ofstream out(backing, fstream::trunc|fstream::binary);
433 return loadKeyFromFile(backing, format, password);
436 vector<XSECCryptoX509*>::size_type SecurityHelper::loadCertificatesFromURL(
437 vector<XSECCryptoX509*>& certs, SOAPTransport& transport, const char* backing, const char* format, const char* password
441 istream& msg = transport.receive();
443 // Check for "not modified" status.
444 if (dynamic_cast<HTTPSOAPTransport*>(&transport) && transport.getStatusCode() == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)
445 throw (long)HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED;
447 // Dump to output file.
448 ofstream out(backing, fstream::trunc|fstream::binary);
452 return loadCertificatesFromFile(certs, backing, format, password);
455 vector<XSECCryptoX509CRL*>::size_type SecurityHelper::loadCRLsFromURL(
456 vector<XSECCryptoX509CRL*>& crls, SOAPTransport& transport, const char* backing, const char* format
461 istream& msg = transport.receive();
463 // Check for "not modified" status.
464 if (dynamic_cast<HTTPSOAPTransport*>(&transport) && transport.getStatusCode() == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)
465 throw (long)HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED;
467 // Dump to output file.
468 ofstream out(backing, fstream::trunc|fstream::binary);
472 return loadCRLsFromFile(crls, backing, format);
475 bool SecurityHelper::matches(const XSECCryptoKey& key1, const XSECCryptoKey& key2)
477 if (key1.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL ||
478 key2.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
479 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("comparison of non-OpenSSL keys not supported");
483 // If one key is public or both, just compare the public key half.
484 if (key1.getKeyType()==XSECCryptoKey::KEY_RSA_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_RSA_PAIR) {
485 if (key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR)
487 const RSA* rsa1 = static_cast<const OpenSSLCryptoKeyRSA&>(key1).getOpenSSLRSA();
488 const RSA* rsa2 = static_cast<const OpenSSLCryptoKeyRSA&>(key2).getOpenSSLRSA();
489 return (rsa1 && rsa2 && BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->e,rsa2->e) == 0);
492 // For a private key, compare the private half.
493 if (key1.getKeyType()==XSECCryptoKey::KEY_RSA_PRIVATE) {
494 if (key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR)
496 const RSA* rsa1 = static_cast<const OpenSSLCryptoKeyRSA&>(key1).getOpenSSLRSA();
497 const RSA* rsa2 = static_cast<const OpenSSLCryptoKeyRSA&>(key2).getOpenSSLRSA();
498 return (rsa1 && rsa2 && BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->d,rsa2->d) == 0);
501 // If one key is public or both, just compare the public key half.
502 if (key1.getKeyType()==XSECCryptoKey::KEY_DSA_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_DSA_PAIR) {
503 if (key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR)
505 const DSA* dsa1 = static_cast<const OpenSSLCryptoKeyDSA&>(key1).getOpenSSLDSA();
506 const DSA* dsa2 = static_cast<const OpenSSLCryptoKeyDSA&>(key2).getOpenSSLDSA();
507 return (dsa1 && dsa2 && BN_cmp(dsa1->pub_key,dsa2->pub_key) == 0);
510 // For a private key, compare the private half.
511 if (key1.getKeyType()==XSECCryptoKey::KEY_DSA_PRIVATE) {
512 if (key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR)
514 const DSA* dsa1 = static_cast<const OpenSSLCryptoKeyDSA&>(key1).getOpenSSLDSA();
515 const DSA* dsa2 = static_cast<const OpenSSLCryptoKeyDSA&>(key2).getOpenSSLDSA();
516 return (dsa1 && dsa2 && BN_cmp(dsa1->priv_key,dsa2->priv_key) == 0);
519 #if defined(XMLTOOLING_XMLSEC_ECC) && defined(XMLTOOLING_OPENSSL_HAVE_EC)
520 // If one key is public or both, just compare the public key half.
521 if (key1.getKeyType()==XSECCryptoKey::KEY_EC_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_EC_PAIR) {
522 if (key2.getKeyType()!=XSECCryptoKey::KEY_EC_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_EC_PAIR)
524 const EC_KEY* ec1 = static_cast<const OpenSSLCryptoKeyEC&>(key1).getOpenSSLEC();
525 const EC_KEY* ec2 = static_cast<const OpenSSLCryptoKeyEC&>(key2).getOpenSSLEC();
528 if (EC_GROUP_cmp(EC_KEY_get0_group(ec1), EC_KEY_get0_group(ec2), nullptr) != 0)
530 return (EC_POINT_cmp(EC_KEY_get0_group(ec1), EC_KEY_get0_public_key(ec1), EC_KEY_get0_public_key(ec2), nullptr) == 0);
533 // For a private key, compare the private half.
534 if (key1.getKeyType()==XSECCryptoKey::KEY_EC_PRIVATE) {
535 if (key2.getKeyType()!=XSECCryptoKey::KEY_EC_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_EC_PAIR)
537 const EC_KEY* ec1 = static_cast<const OpenSSLCryptoKeyEC&>(key1).getOpenSSLEC();
538 const EC_KEY* ec2 = static_cast<const OpenSSLCryptoKeyEC&>(key2).getOpenSSLEC();
539 return (ec1 && ec2 && BN_cmp(EC_KEY_get0_private_key(ec1), EC_KEY_get0_private_key(ec2)) == 0);
543 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("unsupported key type for comparison");
547 string SecurityHelper::doHash(const char* hashAlg, const char* buf, unsigned long buflen, bool toHex)
549 static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
552 const EVP_MD* md = EVP_get_digestbyname(hashAlg);
554 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hashAlg);
558 BIO* chain = BIO_new(BIO_s_mem());
559 BIO* b = BIO_new(BIO_f_md());
561 chain = BIO_push(b, chain);
562 BIO_write(chain, buf, buflen);
565 char digest[EVP_MAX_MD_SIZE];
566 int len = BIO_gets(chain, digest, EVP_MD_size(md));
568 if (len != EVP_MD_size(md)) {
569 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error(
570 "hash result length (%d) did not match expected value (%d)", len, EVP_MD_size(md)
575 for (int i=0; i < len; ++i) {
576 ret += (DIGITS[((unsigned char)(0xF0 & digest[i])) >> 4 ]);
577 ret += (DIGITS[0x0F & digest[i]]);
581 for (int i=0; i < len; ++i) {
588 string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, const char* hash, bool nowrap)
592 if (key.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
593 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-OpenSSL keys not supported");
597 const RSA* rsa = nullptr;
598 const DSA* dsa = nullptr;
599 #if defined(XMLTOOLING_XMLSEC_ECC) && defined(XMLTOOLING_OPENSSL_HAVE_EC)
600 const EC_KEY* ec = nullptr;
603 if (key.getKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_RSA_PAIR) {
604 rsa = static_cast<const OpenSSLCryptoKeyRSA&>(key).getOpenSSLRSA();
606 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
610 else if (key.getKeyType() == XSECCryptoKey::KEY_DSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_DSA_PAIR) {
611 dsa = static_cast<const OpenSSLCryptoKeyDSA&>(key).getOpenSSLDSA();
613 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
617 #if defined(XMLTOOLING_XMLSEC_ECC) && defined(XMLTOOLING_OPENSSL_HAVE_EC)
618 else if (key.getKeyType() == XSECCryptoKey::KEY_EC_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_EC_PAIR) {
619 ec = static_cast<const OpenSSLCryptoKeyEC&>(key).getOpenSSLEC();
621 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
627 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("public key type not supported");
631 const EVP_MD* md=nullptr;
633 md = EVP_get_digestbyname(hash);
635 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
640 BIO* chain = BIO_new(BIO_s_mem());
641 BIO* b = BIO_new(BIO_f_base64());
643 BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
644 chain = BIO_push(b, chain);
646 b = BIO_new(BIO_f_md());
648 chain = BIO_push(b, chain);
652 i2d_RSA_PUBKEY_bio(chain, const_cast<RSA*>(rsa));
654 i2d_DSA_PUBKEY_bio(chain, const_cast<DSA*>(dsa));
655 #if defined(XMLTOOLING_XMLSEC_ECC) && defined(XMLTOOLING_OPENSSL_HAVE_EC)
657 i2d_EC_PUBKEY_bio(chain, const_cast<EC_KEY*>(ec));
662 char digest[EVP_MAX_MD_SIZE];
663 int len = BIO_gets(chain, digest, EVP_MD_size(md));
664 if (len != EVP_MD_size(md)) {
672 BIO_write(chain, digest, len);
675 BUF_MEM* bptr=nullptr;
676 BIO_get_mem_ptr(chain, &bptr);
677 if (bptr && bptr->length > 0)
678 ret.append(bptr->data, bptr->length);
684 string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, const char* hash, bool nowrap)
688 if (cert.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
689 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-OpenSSL keys not supported");
693 const EVP_MD* md=nullptr;
695 md = EVP_get_digestbyname(hash);
697 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
702 const X509* x = static_cast<const OpenSSLCryptoX509&>(cert).getOpenSSLX509();
703 EVP_PKEY* key = X509_get_pubkey(const_cast<X509*>(x));
705 BIO* chain = BIO_new(BIO_s_mem());
706 BIO* b = BIO_new(BIO_f_base64());
708 BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
709 chain = BIO_push(b, chain);
711 b = BIO_new(BIO_f_md());
713 chain = BIO_push(b, chain);
715 i2d_PUBKEY_bio(chain, key);
719 char digest[EVP_MAX_MD_SIZE];
720 int len = BIO_gets(chain, digest, EVP_MD_size(md));
721 if (len != EVP_MD_size(md)) {
729 BIO_write(chain, digest, len);
732 BUF_MEM* bptr=nullptr;
733 BIO_get_mem_ptr(chain, &bptr);
734 if (bptr && bptr->length > 0)
735 ret.append(bptr->data, bptr->length);
740 string SecurityHelper::getDEREncoding(const Credential& cred, const char* hash, bool nowrap)
742 const X509Credential* x509 = dynamic_cast<const X509Credential*>(&cred);
743 if (x509 && !x509->getEntityCertificateChain().empty())
744 return getDEREncoding(*(x509->getEntityCertificateChain().front()), hash, nowrap);
745 else if (cred.getPublicKey())
746 return getDEREncoding(*(cred.getPublicKey()), hash, nowrap);
750 string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool nowrap)
752 return getDEREncoding(key, hash ? "SHA1" : nullptr, nowrap);
755 string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, bool nowrap)
757 return getDEREncoding(cert, hash ? "SHA1" : nullptr, nowrap);
760 string SecurityHelper::getDEREncoding(const Credential& cred, bool hash, bool nowrap)
762 return getDEREncoding(cred, hash ? "SHA1" : nullptr, nowrap);
765 XSECCryptoKey* SecurityHelper::fromDEREncoding(const char* buf, unsigned long buflen, bool base64)
768 XMLByte* decoded=nullptr;
770 decoded = xercesc::Base64::decode(reinterpret_cast<const XMLByte*>(buf), &x);
772 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("base64 decode failed");
777 BIO* b = BIO_new_mem_buf((void*)(base64 ? (char*)decoded : buf), (base64 ? x : buflen));
778 EVP_PKEY* pkey = d2i_PUBKEY_bio(b, nullptr);
781 #ifdef XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE
782 XMLString::release(&decoded);
784 XMLString::release((char**)&decoded);
789 // Now map it to an XSEC wrapper.
790 XSECCryptoKey* ret = nullptr;
792 switch (pkey->type) {
794 ret = new OpenSSLCryptoKeyRSA(pkey);
798 ret = new OpenSSLCryptoKeyDSA(pkey);
801 #if defined(XMLTOOLING_XMLSEC_ECC) && defined(XMLTOOLING_OPENSSL_HAVE_EC)
803 ret = new OpenSSLCryptoKeyEC(pkey);
807 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("unsupported public key type");
810 catch (XSECCryptoException& ex) {
811 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error(ex.getMsg());
820 XSECCryptoKey* SecurityHelper::fromDEREncoding(const XMLCh* buf)
823 XMLByte* decoded = xercesc::Base64::decodeToXMLByte(buf, &x);
825 Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("base64 decode failed");
828 XSECCryptoKey* ret = fromDEREncoding((const char*)decoded, x, false);
829 #ifdef XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE
830 XMLString::release(&decoded);
832 XMLString::release((char**)&decoded);