aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/auth/identity.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/auth/identity.cc')
-rw-r--r--libtransport/src/auth/identity.cc286
1 files changed, 229 insertions, 57 deletions
diff --git a/libtransport/src/auth/identity.cc b/libtransport/src/auth/identity.cc
index bd787b9b6..f56532033 100644
--- a/libtransport/src/auth/identity.cc
+++ b/libtransport/src/auth/identity.cc
@@ -17,90 +17,262 @@
using namespace std;
+// function needed to create the a certificate
+static bool _addRandomSerial(X509 *cert) {
+ unsigned long serial = 0;
+ unsigned char serial_bytes[sizeof(serial)];
+
+ // Construct random positive serial number.
+ RAND_bytes(serial_bytes, sizeof(serial_bytes));
+ serial_bytes[0] &= 0x7F;
+ serial = 0;
+ for (size_t i = 0; i < sizeof(serial_bytes); i++) {
+ serial = (256 * serial) + serial_bytes[i];
+ }
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
+ return true;
+}
+
+static bool _addValidityPeriod(X509 *cert, size_t validityDays) {
+ // Set the validity from now for the specified number of days.
+ X509_gmtime_adj(X509_get_notBefore(cert), (long)0);
+ X509_gmtime_adj(X509_get_notAfter(cert), (long)(60 * 60 * 24 * validityDays));
+ return true;
+}
+
+static bool _addSubjectName(X509 *cert, const char *subjectname) {
+ // Set up the simple subject name and issuer name for the certificate.
+ X509_NAME *name = X509_get_subject_name(cert);
+
+ if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+ (unsigned char *)subjectname, -1, -1, 0)) {
+ if (X509_set_issuer_name(cert, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+static bool _addCertificateExtensionWithContext(X509 *cert, int nid,
+ const char *value) {
+ X509_EXTENSION *extension;
+ X509V3_CTX context;
+
+ X509V3_set_ctx_nodb(&context);
+ X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0);
+ extension = X509V3_EXT_conf_nid(NULL, &context, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+static bool _addCertificateExtension(X509 *cert, int nid, const char *value) {
+ X509_EXTENSION *extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+
+static bool _addExtensions(X509 *cert) {
+ // Add the necessary extensions.
+ if (_addCertificateExtension(cert, NID_basic_constraints,
+ "critical,CA:FALSE") == true) {
+ if (_addCertificateExtension(
+ cert, NID_key_usage,
+ "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,"
+ "keyAgreement") == true) {
+ if (_addCertificateExtension(cert, NID_ext_key_usage, "clientAuth") ==
+ true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+static bool _addKeyIdentifier(X509 *cert) {
+ unsigned char spkid[SHA256_DIGEST_LENGTH];
+ char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH];
+ if (ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(),
+ X509_get_X509_PUBKEY(cert), spkid, NULL)) {
+ for (int i = 0; i < 32; i++) {
+ snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned)spkid[i]);
+ }
+ if (_addCertificateExtension(cert, NID_subject_key_identifier, spkid_hex) ==
+ true) {
+ if (_addCertificateExtensionWithContext(
+ cert, NID_authority_key_identifier, "keyid:always") == true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
namespace transport {
namespace auth {
Identity::Identity(const string &keystore_path, const string &keystore_pwd,
CryptoSuite suite, unsigned int signature_len,
unsigned int validity_days, const string &subject_name)
- : identity_(nullptr), signer_(nullptr) {
- parcSecurity_Init();
-
- bool success = parcPkcs12KeyStore_CreateFile(
- keystore_path.c_str(), keystore_pwd.c_str(), subject_name.c_str(),
- parcCryptoSuite_GetSigningAlgorithm(static_cast<PARCCryptoSuite>(suite)),
- signature_len, validity_days);
+ : cert_(X509_new(), ::X509_free) {
+ // create the file and complete it.
+ // first we create the certificate
- parcAssertTrue(
- success,
- "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d, %d) failed.",
- keystore_path.c_str(), keystore_pwd.c_str(), subject_name.c_str(),
- static_cast<int>(suite), static_cast<int>(signature_len), validity_days);
+ // to create the cert we will need a private key
- PARCIdentityFile *identity_file =
- parcIdentityFile_Create(keystore_path.c_str(), keystore_pwd.c_str());
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
- identity_ =
- parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+ if (suite == CryptoSuite::RSA_SHA512 || suite == CryptoSuite::RSA_SHA256) {
+ RSA *rsa = RSA_new();
+ BIGNUM *pub_exp;
- PARCSigner *signer = parcIdentity_CreateSigner(
- identity_,
- parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite)));
+ pub_exp = BN_new();
- signer_ = make_shared<AsymmetricSigner>(signer);
-
- parcSigner_Release(&signer);
- parcIdentityFile_Release(&identity_file);
+ BN_set_word(pub_exp, RSA_F4);
+ if (1 != RSA_generate_key_ex(rsa, signature_len, pub_exp, NULL))
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa))
+ throw errors::RuntimeException("can't generate the key");
+ } else if (suite == CryptoSuite::ECDSA_SHA256) {
+ int curve_params;
+ switch (signature_len) {
+ case 160u:
+ curve_params = NID_secp160k1;
+ break;
+ case 192u:
+ curve_params = NID_secp192k1;
+ break;
+ case 224u:
+ curve_params = NID_secp224k1;
+ break;
+ case 256u:
+ curve_params = NID_secp256k1;
+ break;
+ default:
+ curve_params = -1;
+ break;
+ }
+ if (curve_params == -1)
+ throw errors::RuntimeException("can't generate the key");
+ EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve_params);
+ if (ec_key == NULL)
+ throw errors::RuntimeException("can't create ecdsa key from curve");
+ EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_generate_key(ec_key) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ if (EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_key) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ } else if (suite == CryptoSuite::DSA_SHA256) {
+ DSA *dsa = DSA_new();
+ unsigned char buffer[32];
+ if (RAND_bytes(buffer, sizeof(buffer)) != 1) {
+ throw errors::RuntimeException("can't generate the key");
+ }
+ if (DSA_generate_parameters_ex(dsa, signature_len, buffer, sizeof(buffer),
+ NULL, NULL, NULL) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (DSA_generate_key(dsa) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (EVP_PKEY_set1_DSA(privateKey.get(), dsa) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ }
+ bool success = true;
+ success = success && (X509_set_version(cert_.get(), 2) == 1); // 2 => X509v3
+ success = success && _addRandomSerial(cert_.get());
+ success = success && _addValidityPeriod(cert_.get(), validity_days);
+ success = success && (X509_set_pubkey(cert_.get(), privateKey.get()) == 1);
+ success = success && _addSubjectName(cert_.get(), subject_name.c_str());
+ success = success && _addExtensions(cert_.get());
+ success =
+ success && (X509_sign(cert_.get(), privateKey.get(), EVP_sha256()) != 0);
+ success = success && _addKeyIdentifier(cert_.get());
+ if (!success) {
+ throw errors::RuntimeException("error while creating the certificate");
+ }
+ // the certificate is created. We create the pkcs12 object to write the p12
+ // file
+ PKCS12 *p12 = PKCS12_create(
+ keystore_pwd.c_str(), "ccnxuser", privateKey.get(), cert_.get(), NULL, 0,
+ 0, 0 /*default iter*/, PKCS12_DEFAULT_ITER /*mac_iter*/, 0);
+ filename_ = keystore_path;
+ int fp = open(filename_.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ if (fp == -1) throw errors::RuntimeException("impossible to create the file");
+ FILE *fp_f = fdopen(fp, "wb");
+ if (fp_f == NULL)
+ throw errors::RuntimeException("impossible to create the file");
+ i2d_PKCS12_fp(fp_f, p12);
+ fclose(fp_f);
+ close(fp);
+ std::shared_ptr<EVP_PKEY> publickey(X509_get_pubkey(cert_.get()),
+ EVP_PKEY_free);
+ signer_ = std::shared_ptr<AsymmetricSigner>(
+ new AsymmetricSigner(suite, privateKey, publickey));
+ signer_->signature_len_ = signature_len;
}
Identity::Identity(string &keystore_path, string &keystore_pwd,
CryptoHashType hash_type)
- : identity_(nullptr), signer_(nullptr) {
- parcSecurity_Init();
-
- PARCIdentityFile *identity_file =
- parcIdentityFile_Create(keystore_path.c_str(), keystore_pwd.c_str());
-
- identity_ =
- parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
-
- PARCSigner *signer = parcIdentity_CreateSigner(
- identity_, static_cast<PARCCryptoHashType>(hash_type));
-
- signer_ = make_shared<AsymmetricSigner>(signer);
-
- parcSigner_Release(&signer);
- parcIdentityFile_Release(&identity_file);
+ : cert_(X509_new(), ::X509_free) {
+ filename_ = keystore_path;
+ pwd_ = keystore_path;
+ // get the key and certificate by first opening the keystore file
+ FILE *p12file = fopen(keystore_path.c_str(), "r");
+ if (p12file == NULL)
+ throw errors::RuntimeException("impossible open keystore");
+ PKCS12 *p12 = d2i_PKCS12_fp(p12file, NULL);
+ EVP_PKEY *privatekey;
+ EVP_PKEY *publickey;
+ X509 *cert = cert_.get();
+ // now we parse the file to get the first key and certificate
+ if (1 != PKCS12_parse(p12, keystore_pwd.c_str(), &privatekey, &cert, NULL))
+ throw errors::RuntimeException("impossible to get the private key");
+ publickey = X509_get_pubkey(cert);
+ // to have the cryptosuite we use the nid number that is used to identify the
+ // suite.
+ CryptoSuite suite = getSuite(X509_get_signature_nid(cert));
+ signer_ = std::shared_ptr<AsymmetricSigner>(new AsymmetricSigner(
+ suite, std::shared_ptr<EVP_PKEY>(privatekey, EVP_PKEY_free),
+ std::shared_ptr<EVP_PKEY>(publickey, EVP_PKEY_free)));
+ PKCS12_free(p12);
}
-Identity::Identity(const Identity &other)
- : identity_(nullptr), signer_(other.signer_) {
- parcSecurity_Init();
- identity_ = parcIdentity_Acquire(other.identity_);
+Identity::Identity(const Identity &other) {
+ pwd_ = other.pwd_;
+ filename_ = other.filename_;
+ signer_ = other.signer_;
+ cert_ = other.cert_;
}
-Identity::Identity(Identity &&other)
- : identity_(nullptr), signer_(move(other.signer_)) {
- parcSecurity_Init();
- identity_ = parcIdentity_Acquire(other.identity_);
- parcIdentity_Release(&other.identity_);
+Identity::Identity(Identity &&other) {
+ signer_ = std::move(other.signer_);
+ other.signer_.reset();
+ cert_ = std::move(other.cert_);
+ other.cert_.reset();
+ pwd_ = other.pwd_;
+ other.pwd_ = "";
+ filename_ = other.filename_;
+ other.filename_ = "";
+ signer_ = other.signer_;
+ other.signer_ = nullptr;
}
-Identity::~Identity() {
- if (identity_) parcIdentity_Release(&identity_);
- parcSecurity_Fini();
-}
+Identity::~Identity() {}
shared_ptr<AsymmetricSigner> Identity::getSigner() const { return signer_; }
-string Identity::getFilename() const {
- return string(parcIdentity_GetFileName(identity_));
-}
+string Identity::getFilename() const { return filename_; }
-string Identity::getPassword() const {
- return string(parcIdentity_GetPassWord(identity_));
+std::shared_ptr<X509> Identity::getCertificate() const { return cert_; }
+std::shared_ptr<EVP_PKEY> Identity::getPrivateKey() const {
+ return signer_->key_;
}
+string Identity::getPassword() const { return pwd_; }
+
Identity Identity::generateIdentity(const string &subject_name) {
string keystore_name = "keystore";
string keystore_password = "password";