123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "dtlsidentity.h"
- #include "cert.h"
- #include "cryptohi.h"
- #include "keyhi.h"
- #include "nsError.h"
- #include "pk11pub.h"
- #include "sechash.h"
- #include "ssl.h"
- #include "mozilla/Sprintf.h"
- namespace mozilla {
- RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
- ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
- if (!slot) {
- return nullptr;
- }
- uint8_t random_name[16];
- SECStatus rv = PK11_GenerateRandomOnSlot(slot, random_name,
- sizeof(random_name));
- if (rv != SECSuccess)
- return nullptr;
- std::string name;
- char chunk[3];
- for (size_t i = 0; i < sizeof(random_name); ++i) {
- SprintfLiteral(chunk, "%.2x", random_name[i]);
- name += chunk;
- }
- std::string subject_name_string = "CN=" + name;
- ScopedCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str()));
- if (!subject_name) {
- return nullptr;
- }
- unsigned char paramBuf[12]; // OIDs are small
- SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) };
- SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
- if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) {
- return nullptr;
- }
- ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID;
- ecdsaParams.data[1] = oidData->oid.len;
- memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len);
- ecdsaParams.len = oidData->oid.len + 2;
- ScopedSECKEYPrivateKey private_key;
- ScopedSECKEYPublicKey public_key;
- SECKEYPublicKey *pubkey;
- private_key =
- PK11_GenerateKeyPair(slot,
- CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey,
- PR_FALSE, PR_TRUE, nullptr);
- if (private_key == nullptr)
- return nullptr;
- public_key = pubkey;
- ScopedCERTSubjectPublicKeyInfo spki(
- SECKEY_CreateSubjectPublicKeyInfo(pubkey));
- if (!spki) {
- return nullptr;
- }
- ScopedCERTCertificateRequest certreq(
- CERT_CreateCertificateRequest(subject_name, spki, nullptr));
- if (!certreq) {
- return nullptr;
- }
- // From 1 day before todayto 30 days after.
- // This is a sort of arbitrary range designed to be valid
- // now with some slack in case the other side expects
- // some before expiry.
- //
- // Note: explicit casts necessary to avoid
- // warning C4307: '*' : integral constant overflow
- static const PRTime oneDay = PRTime(PR_USEC_PER_SEC)
- * PRTime(60) // sec
- * PRTime(60) // min
- * PRTime(24); // hours
- PRTime now = PR_Now();
- PRTime notBefore = now - oneDay;
- PRTime notAfter = now + (PRTime(30) * oneDay);
- ScopedCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
- if (!validity) {
- return nullptr;
- }
- unsigned long serial;
- // Note: This serial in principle could collide, but it's unlikely
- rv = PK11_GenerateRandomOnSlot(slot,
- reinterpret_cast<unsigned char *>(&serial),
- sizeof(serial));
- if (rv != SECSuccess) {
- return nullptr;
- }
- ScopedCERTCertificate certificate(
- CERT_CreateCertificate(serial, subject_name, validity, certreq));
- if (!certificate) {
- return nullptr;
- }
- PLArenaPool *arena = certificate->arena;
- rv = SECOID_SetAlgorithmID(arena, &certificate->signature,
- SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0);
- if (rv != SECSuccess)
- return nullptr;
- // Set version to X509v3.
- *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3;
- certificate->version.len = 1;
- SECItem innerDER;
- innerDER.len = 0;
- innerDER.data = nullptr;
- if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate,
- SEC_ASN1_GET(CERT_CertificateTemplate))) {
- return nullptr;
- }
- SECItem *signedCert = PORT_ArenaZNew(arena, SECItem);
- if (!signedCert) {
- return nullptr;
- }
- rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
- private_key,
- SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
- if (rv != SECSuccess) {
- return nullptr;
- }
- certificate->derCert = *signedCert;
- RefPtr<DtlsIdentity> identity =
- new DtlsIdentity(private_key.forget(), certificate.forget(), ssl_kea_ecdh);
- return identity.forget();
- }
- const std::string DtlsIdentity::DEFAULT_HASH_ALGORITHM = "sha-256";
- nsresult DtlsIdentity::ComputeFingerprint(const std::string algorithm,
- uint8_t *digest,
- size_t size,
- size_t *digest_length) const {
- const UniqueCERTCertificate& c = cert();
- MOZ_ASSERT(c);
- return ComputeFingerprint(c, algorithm, digest, size, digest_length);
- }
- nsresult DtlsIdentity::ComputeFingerprint(const UniqueCERTCertificate& cert,
- const std::string algorithm,
- uint8_t *digest,
- size_t size,
- size_t *digest_length) {
- MOZ_ASSERT(cert);
- HASH_HashType ht;
- if (algorithm == "sha-1") {
- ht = HASH_AlgSHA1;
- } else if (algorithm == "sha-224") {
- ht = HASH_AlgSHA224;
- } else if (algorithm == "sha-256") {
- ht = HASH_AlgSHA256;
- } else if (algorithm == "sha-384") {
- ht = HASH_AlgSHA384;
- } else if (algorithm == "sha-512") {
- ht = HASH_AlgSHA512;
- } else {
- return NS_ERROR_INVALID_ARG;
- }
- const SECHashObject *ho = HASH_GetHashObject(ht);
- MOZ_ASSERT(ho);
- if (!ho) {
- return NS_ERROR_INVALID_ARG;
- }
- MOZ_ASSERT(ho->length >= 20); // Double check
- if (size < ho->length) {
- return NS_ERROR_INVALID_ARG;
- }
- SECStatus rv = HASH_HashBuf(ho->type, digest,
- cert->derCert.data,
- cert->derCert.len);
- if (rv != SECSuccess) {
- return NS_ERROR_FAILURE;
- }
- *digest_length = ho->length;
- return NS_OK;
- }
- } // close namespace
|