diff options
Diffstat (limited to 'libtransport/src/auth/identity.cc')
-rw-r--r-- | libtransport/src/auth/identity.cc | 286 |
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"; |