bool PolicyManager::verifySha256WithEcdsaSignature (const Blob& signature, const SignedBlob& signedBlob, const Blob& publicKeyDer) { // Set signedPortionDigest to the digest of the signed portion of the signedBlob. uint8_t signedPortionDigest[SHA256_DIGEST_LENGTH]; ndn_digestSha256 (signedBlob.signedBuf(), signedBlob.signedSize(), signedPortionDigest); // Verify the signedPortionDigest. // Use a temporary pointer since d2i updates it. const uint8_t *derPointer = publicKeyDer.buf(); EC_KEY *ecPublicKey = d2i_EC_PUBKEY(NULL, &derPointer, publicKeyDer.size()); if (!ecPublicKey) throw UnrecognizedKeyFormatException ("Error decoding public key in d2i_EC_PUBKEY"); int success = ECDSA_verify (NID_sha256, signedPortionDigest, sizeof(signedPortionDigest), (uint8_t *)signature.buf(),signature.size(), ecPublicKey); // Free the public key before checking for success. EC_KEY_free(ecPublicKey); // ECDSA_verify returns 1 for a valid signature. return (success == 1); }
void Encryptor::encryptData (Data& data, const Blob& payload, const Name& keyName, const Blob& key, const EncryptParams& params) { data.getName().append(getNAME_COMPONENT_FOR()).append(keyName); ndn_EncryptAlgorithmType algorithmType = params.getAlgorithmType(); if (algorithmType == ndn_EncryptAlgorithmType_AesCbc || algorithmType == ndn_EncryptAlgorithmType_AesEcb) { EncryptedContent content = encryptSymmetric(payload, key, keyName, params); data.setContent(content.wireEncode(*TlvWireFormat::get())); } else if (algorithmType == ndn_EncryptAlgorithmType_RsaPkcs || algorithmType == ndn_EncryptAlgorithmType_RsaOaep) { // Openssl doesn't have an easy way to get the maximum plain text size, so // try to encrypt the payload first and catch the error if it is too big. try { EncryptedContent content = encryptAsymmetric(payload, key, keyName, params); data.setContent(content.wireEncode(*TlvWireFormat::get())); return; } catch (SecurityException&) { // The payload is larger than the maximum plaintext size. Continue. } // 128-bit nonce. ptr_lib::shared_ptr<vector<uint8_t> > nonceKeyBuffer(new vector<uint8_t>(16)); ndn_Error error; if ((error = CryptoLite::generateRandomBytes (&nonceKeyBuffer->front(), nonceKeyBuffer->size()))) throw runtime_error(ndn_getErrorString(error)); Blob nonceKey(nonceKeyBuffer, false); Name nonceKeyName(keyName); nonceKeyName.append("nonce"); EncryptParams symmetricParams (ndn_EncryptAlgorithmType_AesCbc, AesAlgorithm::BLOCK_SIZE); EncryptedContent nonceContent = encryptSymmetric (payload, nonceKey, nonceKeyName, symmetricParams); EncryptedContent payloadContent = encryptAsymmetric (nonceKey, key, keyName, params); Blob nonceContentEncoding = nonceContent.wireEncode(); Blob payloadContentEncoding = payloadContent.wireEncode(); ptr_lib::shared_ptr<vector<uint8_t> > content(new vector<uint8_t> (nonceContentEncoding.size() + payloadContentEncoding.size())); ndn_memcpy(&content->front(), payloadContentEncoding.buf(), payloadContentEncoding.size()); ndn_memcpy(&content->front() + payloadContentEncoding.size(), nonceContentEncoding.buf(), nonceContentEncoding.size()); data.setContent(Blob(content, false)); } else throw runtime_error("Unsupported encryption method"); }
/** * Decode signatureInfo as a signature info and signatureValue as the related * SignatureValue, and return a new object which is a subclass of Signature. * @param signatureInfo The signature input buffer to decode. * @param signatureValue The signature value input buffer to decode. * @return A new object which is a subclass of Signature. */ ptr_lib::shared_ptr<Signature> decodeSignatureInfoAndValue (const Blob& signatureInfo, const Blob& signatureValue) { return decodeSignatureInfoAndValue (signatureInfo.buf(), signatureInfo.size(), signatureValue.buf(), signatureValue.size()); }
Blob RsaAlgorithm::decrypt (const Blob& keyBits, const Blob& encryptedData, const EncryptParams& params) { TpmPrivateKey privateKey; privateKey.loadPkcs8(keyBits.buf(), keyBits.size()); return privateKey.decrypt (encryptedData.buf(), encryptedData.size(), params.getAlgorithmType()); }
void PrivateKeyStorage::decodeEcPrivateKey (const ptr_lib::shared_ptr<DerNode>& algorithmParameters, const Blob& privateKeyDer, EcPrivateKeyLite& privateKey) { // Find the curveId in EC_KEY_INFO. int curveId = -1; string oidString = algorithmParameters->toVal().toRawStr(); for (size_t i = 0 ; i < ndn_getEcKeyInfoCount(); ++i) { const struct ndn_EcKeyInfo *info = ndn_getEcKeyInfo(i); OID curveOid(info->oidIntegerList, info->oidIntegerListLength); if (curveOid.toString() == oidString) { curveId = info->curveId; break; } } if (curveId == -1) throw SecurityException ("FilePrivateKeyStorage::decodeEcPrivateKey: Unrecognized EC algorithm parameters"); // Get the value in the octet string. ptr_lib::shared_ptr<DerNode> parsedNode = DerNode::parse(privateKeyDer.buf(), 0); DerNode::DerOctetString* octetString = dynamic_cast<DerNode::DerOctetString*> (parsedNode->getChildren()[1].get()); if (!octetString) throw SecurityException ("FilePrivateKeyStorage::decodeEcPrivateKey: Can't get the private key octet string"); Blob octetStringValue = octetString->toVal(); ndn_Error error; if ((error = privateKey.setByCurve(curveId, octetStringValue))) throw SecurityException (string("PrivateKeyStorage::decodeEcPrivateKey ") + ndn_getErrorString(error)); }
void wireDecode (const Blob& input, WireFormat& wireFormat = *WireFormat::getDefaultWireFormat()) { wireDecode(input.buf(), input.size(), wireFormat); }
EncryptKey RsaAlgorithm::deriveEncryptKey(const Blob& keyBits) { TpmPrivateKey privateKey; privateKey.loadPkcs8(keyBits.buf(), keyBits.size()); return EncryptKey(privateKey.derivePublicKey()); }
/** * Verify the RSA signature on the SignedBlob using the given public key. * TODO: Move this general verification code to a more central location. * @param signature The Sha256WithRsaSignature. * @param signedBlob the SignedBlob with the signed portion to verify. * @param publicKeyDer The DER-encoded public key used to verify the signature. * @return true if the signature verifies, false if not. */ static bool verifySha256WithRsaSignature (const Sha256WithRsaSignature* signature, const SignedBlob& signedBlob, const Blob& publicKeyDer) { // Set signedPortionDigest to the digest of the signed portion of the wire encoding. uint8_t signedPortionDigest[SHA256_DIGEST_LENGTH]; // wireEncode returns the cached encoding if available. ndn_digestSha256 (signedBlob.signedBuf(), signedBlob.signedSize(), signedPortionDigest); // Verify the signedPortionDigest. // Use a temporary pointer since d2i updates it. const uint8_t *derPointer = publicKeyDer.buf(); RSA *rsaPublicKey = d2i_RSA_PUBKEY(NULL, &derPointer, publicKeyDer.size()); if (!rsaPublicKey) throw UnrecognizedKeyFormatException("Error decoding public key in d2i_RSAPublicKey"); int success = RSA_verify (NID_sha256, signedPortionDigest, sizeof(signedPortionDigest), (uint8_t *)signature->getSignature().buf(), signature->getSignature().size(), rsaPublicKey); // Free the public key before checking for success. RSA_free(rsaPublicKey); // RSA_verify returns 1 for a valid signature. return (success == 1); }
TEST_F(TestConfigPolicyManager, Refresh10s) { ifstream dataFile((policyConfigDirectory_ + "/testData").c_str()); stringstream encodedData; encodedData << dataFile.rdbuf(); vector<uint8_t> dataBlob; fromBase64(encodedData.str(), dataBlob); ptr_lib::shared_ptr<Data> data(new Data()); data->wireDecode(dataBlob); // This test is needed, since the KeyChain will express interests in unknown // certificates. VerificationResult vr = doVerify(*policyManager_, data); ASSERT_TRUE(vr.hasFurtherSteps_) << "ConfigPolicyManager did not create ValidationRequest for unknown certificate"; ASSERT_EQ(vr.successCount_, 0) << "ConfigPolicyManager called success callback with pending ValidationRequest"; ASSERT_EQ(vr.failureCount_, 0) << "ConfigPolicyManager called failure callback with pending ValidationRequest"; // Now save the cert data to our anchor directory, and wait. // We have to sign it with the current identity or the policy manager will // create an interest for the signing certificate. IdentityCertificate cert; vector<uint8_t> certData; fromBase64(CERT_DUMP, certData); cert.wireDecode(Blob(certData)); keyChain_->signByIdentity(cert, identityName_); Blob signedCertBlob = cert.wireEncode(); string encodedCert = toBase64(signedCertBlob.buf(), signedCertBlob.size(), true); { ofstream certFile(testCertFile_.c_str()); certFile << encodedCert; } // Still too early for refresh to pick it up. vr = doVerify(*policyManager_, data); ASSERT_TRUE(vr.hasFurtherSteps_) << "ConfigPolicyManager refresh occured sooner than specified"; ASSERT_EQ(vr.successCount_, 0) << "ConfigPolicyManager called success callback with pending ValidationRequest"; ASSERT_EQ(vr.failureCount_, 0) << "ConfigPolicyManager called failure callback with pending ValidationRequest"; usleep(6000000); // Now we should find it. vr = doVerify(*policyManager_, data); ASSERT_FALSE(vr.hasFurtherSteps_) << "ConfigPolicyManager did not refresh certificate store"; ASSERT_EQ(vr.successCount_, 1) << "Verification success called " << vr.successCount_ << " times instead of 1"; ASSERT_EQ(vr.failureCount_, 0) << "ConfigPolicyManager did not verify valid signed data"; }
bool PolicyManager::verifyDigestSha256Signature (const Blob& signature, const SignedBlob& signedBlob) { // Set signedPortionDigest to the digest of the signed portion of the signedBlob. uint8_t signedPortionDigest[SHA256_DIGEST_LENGTH]; ndn_digestSha256 (signedBlob.signedBuf(), signedBlob.signedSize(), signedPortionDigest); return signature.size() == sizeof(signedPortionDigest) && ndn_memcmp (signature.buf(), signedPortionDigest, sizeof(signedPortionDigest)) == 0; }
ptr_lib::shared_ptr<PublicKey> PublicKey::fromDer(const Blob& keyDer) { // Use a temporary pointer since d2i updates it. const uint8_t *derPointer = keyDer.buf(); RSA *publicKey = d2i_RSA_PUBKEY(NULL, &derPointer, keyDer.size()); if (!publicKey) throw UnrecognizedKeyFormatException("Error decoding public key DER"); RSA_free(publicKey); return ptr_lib::shared_ptr<PublicKey>(new PublicKey(OID(vector<int>(RSA_OID, RSA_OID + sizeof(RSA_OID))), keyDer)); }
void Data::wireDecode(const Blob& input, WireFormat& wireFormat) { size_t signedPortionBeginOffset, signedPortionEndOffset; wireFormat.decodeData(*this, input.buf(), input.size(), &signedPortionBeginOffset, &signedPortionEndOffset); if (&wireFormat == WireFormat::getDefaultWireFormat()) // This is the default wire encoding. // Take a pointer to the input Blob without copying. setDefaultWireEncoding (SignedBlob(input, signedPortionBeginOffset, signedPortionEndOffset), WireFormat::getDefaultWireFormat()); else setDefaultWireEncoding(SignedBlob(), 0); }
ec_key_st* FilePrivateKeyStorage::decodeEcPrivateKey (const ptr_lib::shared_ptr<DerNode>& algorithmParameters, const Blob& privateKeyDer) { // Find the curveId in EC_KEY_INFO. int curveId = -1; string oidString = algorithmParameters->toVal().toRawStr(); for (size_t i = 0 ; i < sizeof(EC_KEY_INFO) / sizeof(EC_KEY_INFO[0]); ++i) { OID curveOid(EC_KEY_INFO[i].oidIntegerList, EC_KEY_INFO[i].oidIntegerListLength); if (curveOid.toString() == oidString) { curveId = EC_KEY_INFO[i].curveId; break; } } if (curveId == -1) throw SecurityException ("FilePrivateKeyStorage::decodeEcPrivateKey: Unrecognized EC algorithm parameters"); // Get the value in the octet string. ptr_lib::shared_ptr<DerNode> parsedNode = DerNode::parse(privateKeyDer.buf(), 0); DerNode::DerOctetString* octetString = dynamic_cast<DerNode::DerOctetString*> (parsedNode->getChildren()[1].get()); if (!octetString) throw SecurityException ("FilePrivateKeyStorage::decodeEcPrivateKey: Can't get the private key octet string"); Blob octetStringValue = octetString->toVal(); BIGNUM* keyBignum = BN_bin2bn(octetStringValue.buf(), octetStringValue.size(), NULL); if (!keyBignum) { // We don't expect this to happen. throw SecurityException ("FilePrivateKeyStorage::decodeEcPrivateKey: Can't create a BIGNUM for the private key value"); } EC_KEY* privateKey = EC_KEY_new_by_curve_name(curveId); if (!privateKey) { // We don't expect this to happen. BN_free(keyBignum); throw SecurityException ("FilePrivateKeyStorage::decodeEcPrivateKey: Can't create an EC key for the curve ID"); } EC_KEY_set_private_key(privateKey, keyBignum); BN_free(keyBignum); return privateKey; }
Blob DerNode::DerStructure::encode() { DynamicUInt8Vector buffer(10); size_t bufferPosition = 0; updateSize(); encodeHeader(size_); bufferPosition = buffer.copy(&header_[0], header_.size(), bufferPosition); for (size_t i = 0; i < nodeList_.size(); ++i) { DerNode& n = *nodeList_[i]; Blob encodedChild = n.encode(); bufferPosition = buffer.copy (encodedChild.buf(), encodedChild.size(), bufferPosition); } buffer.get()->resize(bufferPosition); return Blob(buffer.get(), false); }
Blob sign(const Blob& data, const Name& keyName, DigestAlgorithm digestAlgorithm = DIGEST_ALGORITHM_SHA256) { return sign(data.buf(), data.size(), keyName, digestAlgorithm); }
Blob decrypt(const Name& keyName, const Blob& data, bool isSymmetric = false) { return decrypt(keyName, data.buf(), data.size(), isSymmetric); }
/** * A utility function to call the normal sqlite3_bind_blob where the value and * length are blob.buf() and blob.size(). */ static int sqlite3_bind_blob (sqlite3_stmt* statement, int index, const Blob& value, void(*destructor)(void*)) { return sqlite3_bind_blob(statement, index, value.buf(), value.size(), destructor); }
Blob FilePrivateKeyStorage::sign (const uint8_t *data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm) { string keyURI = keyName.toUri(); if (!doesKeyExist(keyName, KEY_CLASS_PRIVATE)) throw SecurityException ("FilePrivateKeyStorage::sign: private key doesn't exist"); if (digestAlgorithm != DIGEST_ALGORITHM_SHA256) throw SecurityException ("FilePrivateKeyStorage::sign: Unsupported digest algorithm"); // Read the private key. ifstream file(nameTransform(keyURI, ".pri").c_str()); stringstream base64; base64 << file.rdbuf(); vector<uint8_t> pkcs8Der; fromBase64(base64.str(), pkcs8Der); // The private key is generated by NFD which stores as PKCS #8. Decode it // to find the algorithm OID and the inner private key DER. ptr_lib::shared_ptr<DerNode> parsedNode = DerNode::parse(&pkcs8Der[0], 0); const std::vector<ptr_lib::shared_ptr<DerNode> >& pkcs8Children = parsedNode->getChildren(); // Get the algorithm OID and parameters. const std::vector<ptr_lib::shared_ptr<DerNode> >& algorithmIdChildren = DerNode::getSequence(pkcs8Children, 1).getChildren(); string oidString (dynamic_cast<DerNode::DerOid&>(*algorithmIdChildren[0]).toVal().toRawStr()); ptr_lib::shared_ptr<DerNode> algorithmParameters = algorithmIdChildren[1]; // Get the value of the 3rd child which is the octet string. Blob privateKeyDer = pkcs8Children[2]->toVal(); // Get the digest to sign. uint8_t digest[SHA256_DIGEST_LENGTH]; ndn_digestSha256(data, dataLength, digest); // TODO: use RSA_size, etc. to get the proper size of the signature buffer. uint8_t signatureBits[1000]; unsigned int signatureBitsLength; // Decode the private key and sign. if (oidString == RSA_ENCRYPTION_OID) { // Use a temporary pointer since d2i updates it. const uint8_t* derPointer = privateKeyDer.buf(); rsa_st* privateKey = d2i_RSAPrivateKey(NULL, &derPointer, privateKeyDer.size()); if (!privateKey) throw SecurityException ("FilePrivateKeyStorage::sign: Error decoding the RSA private key DER"); int success = RSA_sign (NID_sha256, digest, sizeof(digest), signatureBits, &signatureBitsLength, privateKey); // Free the private key before checking for success. RSA_free(privateKey); if (!success) throw SecurityException("FilePrivateKeyStorage::sign: Error in RSA_sign"); } else if (oidString == EC_ENCRYPTION_OID) { ec_key_st* privateKey = decodeEcPrivateKey(algorithmParameters, privateKeyDer); int success = ECDSA_sign (NID_sha256, digest, sizeof(digest), signatureBits, &signatureBitsLength, privateKey); // Free the private key before checking for success. EC_KEY_free(privateKey); if (!success) throw SecurityException("FilePrivateKeyStorage::sign: Error in ECDSA_sign"); } else throw SecurityException ("FilePrivateKeyStorage::sign: Unrecognized private key OID"); return Blob(signatureBits, (size_t)signatureBitsLength); }
void FilePrivateKeyStorage::generateKeyPair (const Name& keyName, const KeyParams& params) { if (doesKeyExist(keyName, KEY_CLASS_PUBLIC)) throw SecurityException("Public Key already exists"); if (doesKeyExist(keyName, KEY_CLASS_PRIVATE)) throw SecurityException("Private Key already exists"); Blob publicKeyDer; Blob privateKeyDer; if (params.getKeyType() == KEY_TYPE_RSA) { const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params); BIGNUM* exponent = 0; RSA* rsa = 0; exponent = BN_new(); if (BN_set_word(exponent, RSA_F4) == 1) { rsa = RSA_new(); if (RSA_generate_key_ex(rsa, rsaParams.getKeySize(), exponent, NULL) == 1) { // Encode the public key. int length = i2d_RSA_PUBKEY(rsa, NULL); publicKeyDer = Blob(ptr_lib::make_shared<vector<uint8_t> >(length), false); uint8_t* derPointer = const_cast<uint8_t*>(publicKeyDer.buf()); i2d_RSA_PUBKEY(rsa, &derPointer); // Encode the private key. length = i2d_RSAPrivateKey(rsa, NULL); vector<uint8_t> pkcs1PrivateKeyDer(length); derPointer = &pkcs1PrivateKeyDer[0]; i2d_RSAPrivateKey(rsa, &derPointer); privateKeyDer = encodePkcs8PrivateKey (pkcs1PrivateKeyDer, OID(RSA_ENCRYPTION_OID), ptr_lib::make_shared<DerNode::DerNull>()); } } BN_free(exponent); RSA_free(rsa); } else if (params.getKeyType() == KEY_TYPE_ECDSA) { const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params); OID parametersOid; int curveId = -1; // Find the entry in EC_KEY_INFO. for (size_t i = 0 ; i < sizeof(EC_KEY_INFO) / sizeof(EC_KEY_INFO[0]); ++i) { if (EC_KEY_INFO[i].keySize == ecdsaParams.getKeySize()) { curveId = EC_KEY_INFO[i].curveId; parametersOid.setIntegerList (EC_KEY_INFO[i].oidIntegerList, EC_KEY_INFO[i].oidIntegerListLength); break; } } if (curveId == -1) throw SecurityException("Unsupported keySize for KEY_TYPE_ECDSA"); EC_KEY* ecKey = EC_KEY_new_by_curve_name(curveId); if (ecKey != NULL) { if (EC_KEY_generate_key(ecKey) == 1) { // Encode the public key. int length = i2d_EC_PUBKEY(ecKey, NULL); vector<uint8_t> opensslPublicKeyDer(length); uint8_t* derPointer = &opensslPublicKeyDer[0]; i2d_EC_PUBKEY(ecKey, &derPointer); // Convert the openssl style to ndn-cxx which has the simple AlgorithmIdentifier. // Find the bit string which is the second child. ptr_lib::shared_ptr<DerNode> parsedNode = DerNode::parse (&opensslPublicKeyDer[0], 0); const std::vector<ptr_lib::shared_ptr<DerNode> >& children = parsedNode->getChildren(); publicKeyDer = encodeSubjectPublicKeyInfo (OID(EC_ENCRYPTION_OID), ptr_lib::make_shared<DerNode::DerOid>(parametersOid), children[1]); // Encode the private key. EC_KEY_set_enc_flags(ecKey, EC_PKEY_NO_PARAMETERS | EC_PKEY_NO_PUBKEY); length = i2d_ECPrivateKey(ecKey, NULL); vector<uint8_t> pkcs1PrivateKeyDer(length); derPointer = &pkcs1PrivateKeyDer[0]; i2d_ECPrivateKey(ecKey, &derPointer); privateKeyDer = encodePkcs8PrivateKey (pkcs1PrivateKeyDer, OID(EC_ENCRYPTION_OID), ptr_lib::make_shared<DerNode::DerOid>(parametersOid)); } } EC_KEY_free(ecKey); } else throw SecurityException("Unsupported key type"); string keyUri = keyName.toUri(); string publicKeyFilePath = nameTransform(keyUri, ".pub"); string privateKeyFilePath = nameTransform(keyUri, ".pri"); ofstream publicKeyFile(publicKeyFilePath.c_str()); publicKeyFile << toBase64(publicKeyDer.buf(), publicKeyDer.size(), true); ofstream privateKeyFile(privateKeyFilePath.c_str()); privateKeyFile << toBase64(privateKeyDer.buf(), privateKeyDer.size(), true); ::chmod(publicKeyFilePath.c_str(), S_IRUSR | S_IRGRP | S_IROTH); ::chmod(privateKeyFilePath.c_str(), S_IRUSR); }
/** * Decode the input and update this Schedule. * @param input The input byte array to be decoded as an immutable Blob. */ void wireDecode(const Blob& input) { wireDecode(input.buf(), input.size()); }
static ptr_lib::shared_ptr<DerNode> parse(const Blob& input, size_t startIdx = 0) { return parse(input.buf(), input.size(), startIdx); }
/** * Wrap sqlite3_bind_blob to bind the blob to the statement. * @param index The binding position. * @param blob The Blob with the byte buffer to bind. * @param bufIsStatic (optional) If true, use SQLITE_STATIC to not copy the * blob's byte buffer, which must remain valid until stored. If false or * omitted, use SQLITE_TRANSIENT to copy the byte buffer. * @return SQLite result value. */ int bind(int index, const Blob& blob, bool bufIsStatic = false) { return bind(index, blob.buf(), blob.size(), bufIsStatic); }