/*
- * Copyright 2001-2008 Internet2
+ * Copyright 2001-2010 Internet2
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "internal.h"
#include "logging.h"
+#include "io/HTTPResponse.h"
#include "security/OpenSSLCryptoX509CRL.h"
#include "security/SecurityHelper.h"
+#include "security/X509Credential.h"
+#include "soap/HTTPSOAPTransport.h"
#include "util/NDC.h"
#include <fstream>
+#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
+#include <xsec/enc/XSECCryptoException.hpp>
#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
+#include <xercesc/util/Base64.hpp>
using namespace xmltooling::logging;
using namespace xmltooling;
return 0;
}
+const char* SecurityHelper::guessEncodingFormat(const char* pathname)
+{
+ const char* format=nullptr;
+ BIO* in=BIO_new(BIO_s_file_internal());
+ if (in && BIO_read_filename(in, pathname)>0) {
+ const int READSIZE = 1;
+ char buf[READSIZE];
+ int mark;
+
+ // Examine the first byte.
+ try {
+ if ((mark = BIO_tell(in)) < 0)
+ throw XMLSecurityException("Error loading file: BIO_tell() can't get the file position.");
+ if (BIO_read(in, buf, READSIZE) <= 0)
+ throw XMLSecurityException("Error loading file: BIO_read() can't read from the stream.");
+ if (BIO_seek(in, mark) < 0)
+ throw XMLSecurityException("Error loading file: BIO_seek() can't reset the file position.");
+ }
+ catch (exception&) {
+ log_openssl();
+ BIO_free(in);
+ throw;
+ }
+
+ // Check the first byte of the file. If it's some kind of DER-encoded structure
+ // (including PKCS12), it will begin with ASCII 048. Otherwise, assume it's PEM.
+ if (buf[0] != 48) {
+ format = "PEM";
+ }
+ else {
+ // Here we know it's DER-encoded, now try to parse it as a PKCS12 ASN.1 structure.
+ // If it fails, must be another kind of DER-encoded structure.
+ PKCS12* p12;
+ if ((p12=d2i_PKCS12_bio(in, nullptr)) == nullptr) {
+ format = "DER";
+ }
+ else {
+ format = "PKCS12";
+ PKCS12_free(p12);
+ }
+ }
+ }
+ if (in)
+ BIO_free(in);
+ if (format)
+ return format;
+ throw XMLSecurityException("Unable to determine encoding for file ($1).", params(1,pathname));
+}
+
XSECCryptoKey* SecurityHelper::loadKeyFromFile(const char* pathname, const char* format, const char* password)
{
#ifdef _DEBUG
log.info("loading private key from file (%s)", pathname);
// Native objects.
- PKCS12* p12=NULL;
- EVP_PKEY* pkey=NULL;
+ PKCS12* p12=nullptr;
+ EVP_PKEY* pkey=nullptr;
BIO* in=BIO_new(BIO_s_file_internal());
if (in && BIO_read_filename(in, pathname)>0) {
// If the format isn't set, try and guess it.
- if (!format) {
+ if (!format || !*format) {
const int READSIZE = 1;
char buf[READSIZE];
int mark;
else {
// Here we know it's DER-encoded, now try to parse it as a PKCS12 ASN.1 structure.
// If it fails, must be another kind of DER-encoded structure.
- if ((p12=d2i_PKCS12_bio(in, NULL)) == NULL) {
+ if ((p12=d2i_PKCS12_bio(in, nullptr)) == nullptr) {
format = "DER";
if (BIO_seek(in, mark) < 0) {
log_openssl();
// The format should be known, so parse accordingly.
if (!strcmp(format, "PEM")) {
- pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback, const_cast<char*>(password));
+ pkey = PEM_read_bio_PrivateKey(in, nullptr, passwd_callback, const_cast<char*>(password));
}
else if (!strcmp(format, "DER")) {
- pkey=d2i_PrivateKey_bio(in, NULL);
+ pkey=d2i_PrivateKey_bio(in, nullptr);
}
else if (!strcmp(format, "PKCS12")) {
if (!p12)
- p12 = d2i_PKCS12_bio(in, NULL);
+ p12 = d2i_PKCS12_bio(in, nullptr);
if (p12) {
- X509* x=NULL;
- PKCS12_parse(p12, const_cast<char*>(password), &pkey, &x, NULL);
+ X509* x=nullptr;
+ PKCS12_parse(p12, const_cast<char*>(password), &pkey, &x, nullptr);
PKCS12_free(p12);
X509_free(x);
}
// Now map it to an XSEC wrapper.
if (pkey) {
- XSECCryptoKey* ret=NULL;
+ XSECCryptoKey* ret=nullptr;
switch (pkey->type) {
case EVP_PKEY_RSA:
ret=new OpenSSLCryptoKeyRSA(pkey);
vector<XSECCryptoX509*>::size_type count = certs.size();
// Native objects.
- X509* x=NULL;
- PKCS12* p12=NULL;
+ X509* x=nullptr;
+ PKCS12* p12=nullptr;
BIO* in=BIO_new(BIO_s_file_internal());
if (in && BIO_read_filename(in, pathname)>0) {
// If the format isn't set, try and guess it.
- if (!format) {
+ if (!format || !*format) {
const int READSIZE = 1;
char buf[READSIZE];
int mark;
else {
// Here we know it's DER-encoded, now try to parse it as a PKCS12 ASN.1 structure.
// If it fails, must be another kind of DER-encoded structure.
- if ((p12=d2i_PKCS12_bio(in, NULL)) == NULL) {
+ if ((p12=d2i_PKCS12_bio(in, nullptr)) == nullptr) {
format = "DER";
if (BIO_seek(in, mark) < 0) {
log_openssl();
// The format should be known, so parse accordingly.
if (!strcmp(format, "PEM")) {
- while (x=PEM_read_bio_X509(in, NULL, NULL, NULL)) {
+ while (x=PEM_read_bio_X509(in, nullptr, nullptr, nullptr)) {
certs.push_back(new OpenSSLCryptoX509(x));
X509_free(x);
}
}
else if (!strcmp(format, "DER")) {
- x=d2i_X509_bio(in, NULL);
+ x=d2i_X509_bio(in, nullptr);
if (x) {
certs.push_back(new OpenSSLCryptoX509(x));
X509_free(x);
}
else if (!strcmp(format, "PKCS12")) {
if (!p12)
- p12 = d2i_PKCS12_bio(in, NULL);
+ p12 = d2i_PKCS12_bio(in, nullptr);
if (p12) {
- EVP_PKEY* pkey=NULL;
+ EVP_PKEY* pkey=nullptr;
STACK_OF(X509)* CAstack = sk_X509_new_null();
PKCS12_parse(p12, const_cast<char*>(password), &pkey, &x, &CAstack);
PKCS12_free(p12);
BIO* in=BIO_new(BIO_s_file_internal());
if (in && BIO_read_filename(in, pathname)>0) {
// If the format isn't set, try and guess it.
- if (!format) {
+ if (!format || !*format) {
const int READSIZE = 1;
char buf[READSIZE];
int mark;
log.debug("CRL encoding format for (%s) dynamically resolved as (%s)", pathname, format);
}
- X509_CRL* crl=NULL;
+ X509_CRL* crl=nullptr;
if (!strcmp(format, "PEM")) {
- while (crl=PEM_read_bio_X509_CRL(in, NULL, NULL, NULL)) {
+ while (crl=PEM_read_bio_X509_CRL(in, nullptr, nullptr, nullptr)) {
crls.push_back(new OpenSSLCryptoX509CRL(crl));
X509_CRL_free(crl);
}
}
else if (!strcmp(format, "DER")) {
- crl=d2i_X509_CRL_bio(in, NULL);
+ crl=d2i_X509_CRL_bio(in, nullptr);
if (crl) {
crls.push_back(new OpenSSLCryptoX509CRL(crl));
X509_CRL_free(crl);
transport.send();
istream& msg = transport.receive();
+ // Check for "not modified" status.
+ if (dynamic_cast<HTTPSOAPTransport*>(&transport) && transport.getStatusCode() == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)
+ throw (long)HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED;
+
// Dump to output file.
ofstream out(backing, fstream::trunc|fstream::binary);
out << msg.rdbuf();
transport.send();
istream& msg = transport.receive();
+ // Check for "not modified" status.
+ if (dynamic_cast<HTTPSOAPTransport*>(&transport) && transport.getStatusCode() == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)
+ throw (long)HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED;
+
// Dump to output file.
ofstream out(backing, fstream::trunc|fstream::binary);
out << msg.rdbuf();
transport.send();
istream& msg = transport.receive();
+ // Check for "not modified" status.
+ if (dynamic_cast<HTTPSOAPTransport*>(&transport) && transport.getStatusCode() == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)
+ throw (long)HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED;
+
// Dump to output file.
ofstream out(backing, fstream::trunc|fstream::binary);
out << msg.rdbuf();
return loadCRLsFromFile(crls, backing, format);
}
-bool SecurityHelper::matches(const XSECCryptoKey* key1, const XSECCryptoKey* key2)
+bool SecurityHelper::matches(const XSECCryptoKey& key1, const XSECCryptoKey& key2)
{
- if (key1->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL ||
- key2->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
+ if (key1.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL ||
+ key2.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("comparison of non-OpenSSL keys not supported");
return false;
}
// If one key is public or both, just compare the public key half.
- if (key1->getKeyType()==XSECCryptoKey::KEY_RSA_PUBLIC || key1->getKeyType()==XSECCryptoKey::KEY_RSA_PAIR) {
- if (key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PUBLIC && key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR)
+ if (key1.getKeyType()==XSECCryptoKey::KEY_RSA_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_RSA_PAIR) {
+ if (key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR)
return false;
- const RSA* rsa1 = static_cast<const OpenSSLCryptoKeyRSA*>(key1)->getOpenSSLRSA();
- const RSA* rsa2 = static_cast<const OpenSSLCryptoKeyRSA*>(key2)->getOpenSSLRSA();
- return (BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->e,rsa2->e) == 0);
+ const RSA* rsa1 = static_cast<const OpenSSLCryptoKeyRSA&>(key1).getOpenSSLRSA();
+ const RSA* rsa2 = static_cast<const OpenSSLCryptoKeyRSA&>(key2).getOpenSSLRSA();
+ return (rsa1 && rsa2 && BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->e,rsa2->e) == 0);
}
// For a private key, compare the private half.
- if (key1->getKeyType()==XSECCryptoKey::KEY_RSA_PRIVATE) {
- if (key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PRIVATE && key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR)
+ if (key1.getKeyType()==XSECCryptoKey::KEY_RSA_PRIVATE) {
+ if (key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR)
return false;
- const RSA* rsa1 = static_cast<const OpenSSLCryptoKeyRSA*>(key1)->getOpenSSLRSA();
- const RSA* rsa2 = static_cast<const OpenSSLCryptoKeyRSA*>(key2)->getOpenSSLRSA();
- return (BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->d,rsa2->d) == 0);
+ const RSA* rsa1 = static_cast<const OpenSSLCryptoKeyRSA&>(key1).getOpenSSLRSA();
+ const RSA* rsa2 = static_cast<const OpenSSLCryptoKeyRSA&>(key2).getOpenSSLRSA();
+ return (rsa1 && rsa2 && BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->d,rsa2->d) == 0);
}
// If one key is public or both, just compare the public key half.
- if (key1->getKeyType()==XSECCryptoKey::KEY_DSA_PUBLIC || key1->getKeyType()==XSECCryptoKey::KEY_DSA_PAIR) {
- if (key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PUBLIC && key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR)
+ if (key1.getKeyType()==XSECCryptoKey::KEY_DSA_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_DSA_PAIR) {
+ if (key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR)
return false;
- const DSA* dsa1 = static_cast<const OpenSSLCryptoKeyDSA*>(key1)->getOpenSSLDSA();
- const DSA* dsa2 = static_cast<const OpenSSLCryptoKeyDSA*>(key2)->getOpenSSLDSA();
- return (BN_cmp(dsa1->pub_key,dsa2->pub_key) == 0);
+ const DSA* dsa1 = static_cast<const OpenSSLCryptoKeyDSA&>(key1).getOpenSSLDSA();
+ const DSA* dsa2 = static_cast<const OpenSSLCryptoKeyDSA&>(key2).getOpenSSLDSA();
+ return (dsa1 && dsa2 && BN_cmp(dsa1->pub_key,dsa2->pub_key) == 0);
}
// For a private key, compare the private half.
- if (key1->getKeyType()==XSECCryptoKey::KEY_DSA_PRIVATE) {
- if (key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PRIVATE && key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR)
+ if (key1.getKeyType()==XSECCryptoKey::KEY_DSA_PRIVATE) {
+ if (key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR)
return false;
- const DSA* dsa1 = static_cast<const OpenSSLCryptoKeyDSA*>(key1)->getOpenSSLDSA();
- const DSA* dsa2 = static_cast<const OpenSSLCryptoKeyDSA*>(key2)->getOpenSSLDSA();
- return (BN_cmp(dsa1->priv_key,dsa2->priv_key) == 0);
+ const DSA* dsa1 = static_cast<const OpenSSLCryptoKeyDSA&>(key1).getOpenSSLDSA();
+ const DSA* dsa2 = static_cast<const OpenSSLCryptoKeyDSA&>(key2).getOpenSSLDSA();
+ return (dsa1 && dsa2 && BN_cmp(dsa1->priv_key,dsa2->priv_key) == 0);
}
Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("unsupported key type for comparison");
return false;
}
+
+string SecurityHelper::doHash(const char* hashAlg, const char* buf, unsigned long buflen, bool toHex)
+{
+ static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ string ret;
+
+ const EVP_MD* md = EVP_get_digestbyname(hashAlg);
+ if (!md) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hashAlg);
+ return ret;
+ }
+
+ BIO* chain = BIO_new(BIO_s_mem());
+ BIO* b = BIO_new(BIO_f_md());
+ BIO_set_md(b, md);
+ chain = BIO_push(b, chain);
+ BIO_write(chain, buf, buflen);
+ BIO_flush(chain);
+
+ char digest[EVP_MAX_MD_SIZE];
+ int len = BIO_gets(chain, digest, EVP_MD_size(md));
+ BIO_free_all(chain);
+ if (len != EVP_MD_size(md)) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error(
+ "hash result length (%d) did not match expected value (%d)", len, EVP_MD_size(md)
+ );
+ return ret;
+ }
+ if (toHex) {
+ for (int i=0; i < len; ++i) {
+ ret += (DIGITS[((unsigned char)(0xF0 & digest[i])) >> 4 ]);
+ ret += (DIGITS[0x0F & digest[i]]);
+ }
+ }
+ else {
+ for (int i=0; i < len; ++i) {
+ ret += digest[i];
+ }
+ }
+ return ret;
+}
+
+string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, const char* hash, bool nowrap)
+{
+ string ret;
+
+ if (key.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-OpenSSL keys not supported");
+ return ret;
+ }
+
+ if (key.getKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_RSA_PAIR) {
+ const RSA* rsa = static_cast<const OpenSSLCryptoKeyRSA&>(key).getOpenSSLRSA();
+ if (!rsa) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
+ return ret;
+ }
+ const EVP_MD* md=nullptr;
+ if (hash) {
+ md = EVP_get_digestbyname(hash);
+ if (!md) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
+ return ret;
+ }
+ }
+ BIO* chain = BIO_new(BIO_s_mem());
+ BIO* b = BIO_new(BIO_f_base64());
+ if (nowrap)
+ BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
+ chain = BIO_push(b, chain);
+ if (md) {
+ b = BIO_new(BIO_f_md());
+ BIO_set_md(b, md);
+ chain = BIO_push(b, chain);
+ }
+ i2d_RSA_PUBKEY_bio(chain, const_cast<RSA*>(rsa));
+ BIO_flush(chain);
+ if (md) {
+ char digest[EVP_MAX_MD_SIZE];
+ int len = BIO_gets(chain, digest, EVP_MD_size(md));
+ if (len != EVP_MD_size(md)) {
+ BIO_free_all(chain);
+ return ret;
+ }
+ b = BIO_pop(chain);
+ BIO_free(chain);
+ chain = b;
+ BIO_reset(chain);
+ BIO_write(chain, digest, len);
+ BIO_flush(chain);
+ }
+ BUF_MEM* bptr=nullptr;
+ BIO_get_mem_ptr(chain, &bptr);
+ if (bptr && bptr->length > 0)
+ ret.append(bptr->data, bptr->length);
+ BIO_free_all(chain);
+ }
+ else if (key.getKeyType() == XSECCryptoKey::KEY_DSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_DSA_PAIR) {
+ const DSA* dsa = static_cast<const OpenSSLCryptoKeyDSA&>(key).getOpenSSLDSA();
+ if (!dsa) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
+ return ret;
+ }
+ const EVP_MD* md=nullptr;
+ if (hash) {
+ md = EVP_get_digestbyname(hash);
+ if (!md) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
+ return ret;
+ }
+ }
+ BIO* chain = BIO_new(BIO_s_mem());
+ BIO* b = BIO_new(BIO_f_base64());
+ if (nowrap)
+ BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
+ chain = BIO_push(b, chain);
+ if (md) {
+ b = BIO_new(BIO_f_md());
+ BIO_set_md(b, md);
+ chain = BIO_push(b, chain);
+ }
+ i2d_DSA_PUBKEY_bio(chain, const_cast<DSA*>(dsa));
+ BIO_flush(chain);
+ if (md) {
+ char digest[EVP_MAX_MD_SIZE];
+ int len = BIO_gets(chain, digest, EVP_MD_size(md));
+ if (len != EVP_MD_size(md)) {
+ BIO_free_all(chain);
+ return ret;
+ }
+ b = BIO_pop(chain);
+ BIO_free(chain);
+ chain = b;
+ BIO_reset(chain);
+ BIO_write(chain, digest, len);
+ BIO_flush(chain);
+ }
+ BUF_MEM* bptr=nullptr;
+ BIO_get_mem_ptr(chain, &bptr);
+ if (bptr && bptr->length > 0)
+ ret.append(bptr->data, bptr->length);
+ BIO_free_all(chain);
+ }
+ else {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-RSA/DSA public keys not supported");
+ }
+ return ret;
+}
+
+string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, const char* hash, bool nowrap)
+{
+ string ret;
+
+ if (cert.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-OpenSSL keys not supported");
+ return ret;
+ }
+
+ const EVP_MD* md=nullptr;
+ if (hash) {
+ md = EVP_get_digestbyname(hash);
+ if (!md) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
+ return ret;
+ }
+ }
+
+ const X509* x = static_cast<const OpenSSLCryptoX509&>(cert).getOpenSSLX509();
+ EVP_PKEY* key = X509_get_pubkey(const_cast<X509*>(x));
+
+ BIO* chain = BIO_new(BIO_s_mem());
+ BIO* b = BIO_new(BIO_f_base64());
+ if (nowrap)
+ BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
+ chain = BIO_push(b, chain);
+ if (md) {
+ b = BIO_new(BIO_f_md());
+ BIO_set_md(b, md);
+ chain = BIO_push(b, chain);
+ }
+ i2d_PUBKEY_bio(chain, key);
+ EVP_PKEY_free(key);
+ BIO_flush(chain);
+ if (md) {
+ char digest[EVP_MAX_MD_SIZE];
+ int len = BIO_gets(chain, digest, EVP_MD_size(md));
+ if (len != EVP_MD_size(md)) {
+ BIO_free_all(chain);
+ return ret;
+ }
+ b = BIO_pop(chain);
+ BIO_free(chain);
+ chain = b;
+ BIO_reset(chain);
+ BIO_write(chain, digest, len);
+ BIO_flush(chain);
+ }
+ BUF_MEM* bptr=nullptr;
+ BIO_get_mem_ptr(chain, &bptr);
+ if (bptr && bptr->length > 0)
+ ret.append(bptr->data, bptr->length);
+ BIO_free_all(chain);
+ return ret;
+}
+
+string SecurityHelper::getDEREncoding(const Credential& cred, const char* hash, bool nowrap)
+{
+ const X509Credential* x509 = dynamic_cast<const X509Credential*>(&cred);
+ if (x509 && !x509->getEntityCertificateChain().empty())
+ return getDEREncoding(*(x509->getEntityCertificateChain().front()), hash, nowrap);
+ else if (cred.getPublicKey())
+ return getDEREncoding(*(cred.getPublicKey()), hash, nowrap);
+ return "";
+}
+
+string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool nowrap)
+{
+ return getDEREncoding(key, hash ? "SHA1" : nullptr, nowrap);
+}
+
+string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, bool nowrap)
+{
+ return getDEREncoding(cert, hash ? "SHA1" : nullptr, nowrap);
+}
+
+string SecurityHelper::getDEREncoding(const Credential& cred, bool hash, bool nowrap)
+{
+ return getDEREncoding(cred, hash ? "SHA1" : nullptr, nowrap);
+}
+
+XSECCryptoKey* SecurityHelper::fromDEREncoding(const char* buf, unsigned long buflen, bool base64)
+{
+ xsecsize_t x;
+ XMLByte* decoded=nullptr;
+ if (base64) {
+ decoded = xercesc::Base64::decode(reinterpret_cast<const XMLByte*>(buf), &x);
+ if (!decoded) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("base64 decode failed");
+ return nullptr;
+ }
+ }
+
+ BIO* b = BIO_new_mem_buf((void*)(base64 ? (char*)decoded : buf), (base64 ? x : buflen));
+ EVP_PKEY* pkey = d2i_PUBKEY_bio(b, nullptr);
+ BIO_free(b);
+ if (base64) {
+#ifdef XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE
+ XMLString::release(&decoded);
+#else
+ XMLString::release((char**)&decoded);
+#endif
+ }
+
+ if (pkey) {
+ // Now map it to an XSEC wrapper.
+ XSECCryptoKey* ret = nullptr;
+ try {
+ switch (pkey->type) {
+ case EVP_PKEY_RSA:
+ ret = new OpenSSLCryptoKeyRSA(pkey);
+ break;
+
+ case EVP_PKEY_DSA:
+ ret = new OpenSSLCryptoKeyDSA(pkey);
+ break;
+
+ default:
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("unsupported public key type");
+ }
+ }
+ catch (XSECCryptoException& ex) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error(ex.getMsg());
+ }
+ EVP_PKEY_free(pkey);
+ return ret;
+ }
+
+ return nullptr;
+}
+
+XSECCryptoKey* SecurityHelper::fromDEREncoding(const XMLCh* buf)
+{
+ xsecsize_t x;
+ XMLByte* decoded = xercesc::Base64::decodeToXMLByte(buf, &x);
+ if (!decoded) {
+ Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("base64 decode failed");
+ return nullptr;
+ }
+ XSECCryptoKey* ret = fromDEREncoding((const char*)decoded, x, false);
+#ifdef XMLTOOLING_XERCESC_HAS_XMLBYTE_RELEASE
+ XMLString::release(&decoded);
+#else
+ XMLString::release((char**)&decoded);
+#endif
+ return ret;
+}