LCOV - code coverage report
Current view: top level - media/mtransport - dtlsidentity.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 104 1.9 %
Date: 2017-07-14 16:53:18 Functions: 2 5 40.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "dtlsidentity.h"
       8             : 
       9             : #include "cert.h"
      10             : #include "cryptohi.h"
      11             : #include "keyhi.h"
      12             : #include "nsError.h"
      13             : #include "pk11pub.h"
      14             : #include "sechash.h"
      15             : #include "ssl.h"
      16             : 
      17             : #include "mozilla/Sprintf.h"
      18             : 
      19             : namespace mozilla {
      20             : 
      21           0 : RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
      22           0 :   UniquePK11SlotInfo slot(PK11_GetInternalSlot());
      23           0 :   if (!slot) {
      24           0 :     return nullptr;
      25             :   }
      26             : 
      27             :   uint8_t random_name[16];
      28             : 
      29           0 :   SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), random_name,
      30           0 :                                            sizeof(random_name));
      31           0 :   if (rv != SECSuccess)
      32           0 :     return nullptr;
      33             : 
      34           0 :   std::string name;
      35             :   char chunk[3];
      36           0 :   for (unsigned char r_name : random_name) {
      37           0 :     SprintfLiteral(chunk, "%.2x", r_name);
      38           0 :     name += chunk;
      39             :   }
      40             : 
      41           0 :   std::string subject_name_string = "CN=" + name;
      42           0 :   UniqueCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str()));
      43           0 :   if (!subject_name) {
      44           0 :     return nullptr;
      45             :   }
      46             : 
      47             :   unsigned char paramBuf[12]; // OIDs are small
      48           0 :   SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) };
      49           0 :   SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
      50           0 :   if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) {
      51           0 :     return nullptr;
      52             :   }
      53           0 :   ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID;
      54           0 :   ecdsaParams.data[1] = oidData->oid.len;
      55           0 :   memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len);
      56           0 :   ecdsaParams.len = oidData->oid.len + 2;
      57             : 
      58             :   SECKEYPublicKey *pubkey;
      59             :   UniqueSECKEYPrivateKey private_key(
      60             :       PK11_GenerateKeyPair(slot.get(),
      61             :                            CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey,
      62           0 :                            PR_FALSE, PR_TRUE, nullptr));
      63           0 :   if (private_key == nullptr)
      64           0 :     return nullptr;
      65           0 :   UniqueSECKEYPublicKey public_key(pubkey);
      66           0 :   pubkey = nullptr;
      67             : 
      68             :   UniqueCERTSubjectPublicKeyInfo spki(
      69           0 :       SECKEY_CreateSubjectPublicKeyInfo(public_key.get()));
      70           0 :   if (!spki) {
      71           0 :     return nullptr;
      72             :   }
      73             : 
      74             :   UniqueCERTCertificateRequest certreq(
      75           0 :       CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr));
      76           0 :   if (!certreq) {
      77           0 :     return nullptr;
      78             :   }
      79             : 
      80             :   // From 1 day before todayto 30 days after.
      81             :   // This is a sort of arbitrary range designed to be valid
      82             :   // now with some slack in case the other side expects
      83             :   // some before expiry.
      84             :   //
      85             :   // Note: explicit casts necessary to avoid
      86             :   //       warning C4307: '*' : integral constant overflow
      87             :   static const PRTime oneDay = PRTime(PR_USEC_PER_SEC)
      88             :                              * PRTime(60)  // sec
      89             :                              * PRTime(60)  // min
      90             :                              * PRTime(24); // hours
      91           0 :   PRTime now = PR_Now();
      92           0 :   PRTime notBefore = now - oneDay;
      93           0 :   PRTime notAfter = now + (PRTime(30) * oneDay);
      94             : 
      95           0 :   UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
      96           0 :   if (!validity) {
      97           0 :     return nullptr;
      98             :   }
      99             : 
     100             :   unsigned long serial;
     101             :   // Note: This serial in principle could collide, but it's unlikely
     102           0 :   rv = PK11_GenerateRandomOnSlot(slot.get(),
     103             :                                  reinterpret_cast<unsigned char *>(&serial),
     104           0 :                                  sizeof(serial));
     105           0 :   if (rv != SECSuccess) {
     106           0 :     return nullptr;
     107             :   }
     108             : 
     109             :   UniqueCERTCertificate certificate(
     110             :       CERT_CreateCertificate(serial, subject_name.get(), validity.get(),
     111           0 :                              certreq.get()));
     112           0 :   if (!certificate) {
     113           0 :     return nullptr;
     114             :   }
     115             : 
     116           0 :   PLArenaPool *arena = certificate->arena;
     117             : 
     118           0 :   rv = SECOID_SetAlgorithmID(arena, &certificate->signature,
     119           0 :                              SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, nullptr);
     120           0 :   if (rv != SECSuccess)
     121           0 :     return nullptr;
     122             : 
     123             :   // Set version to X509v3.
     124           0 :   *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3;
     125           0 :   certificate->version.len = 1;
     126             : 
     127             :   SECItem innerDER;
     128           0 :   innerDER.len = 0;
     129           0 :   innerDER.data = nullptr;
     130             : 
     131           0 :   if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(),
     132             :                           SEC_ASN1_GET(CERT_CertificateTemplate))) {
     133           0 :     return nullptr;
     134             :   }
     135             : 
     136           0 :   SECItem *signedCert = PORT_ArenaZNew(arena, SECItem);
     137           0 :   if (!signedCert) {
     138           0 :     return nullptr;
     139             :   }
     140             : 
     141           0 :   rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
     142             :                        private_key.get(),
     143           0 :                        SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
     144           0 :   if (rv != SECSuccess) {
     145           0 :     return nullptr;
     146             :   }
     147           0 :   certificate->derCert = *signedCert;
     148             : 
     149           0 :   RefPtr<DtlsIdentity> identity = new DtlsIdentity(Move(private_key),
     150           0 :                                                    Move(certificate),
     151           0 :                                                    ssl_kea_ecdh);
     152           0 :   return identity.forget();
     153             : }
     154             : 
     155           3 : const std::string DtlsIdentity::DEFAULT_HASH_ALGORITHM = "sha-256";
     156             : 
     157           0 : nsresult DtlsIdentity::ComputeFingerprint(const std::string algorithm,
     158             :                                           uint8_t *digest,
     159             :                                           size_t size,
     160             :                                           size_t *digest_length) const {
     161           0 :   const UniqueCERTCertificate& c = cert();
     162           0 :   MOZ_ASSERT(c);
     163             : 
     164           0 :   return ComputeFingerprint(c, algorithm, digest, size, digest_length);
     165             : }
     166             : 
     167           0 : nsresult DtlsIdentity::ComputeFingerprint(const UniqueCERTCertificate& cert,
     168             :                                           const std::string algorithm,
     169             :                                           uint8_t *digest,
     170             :                                           size_t size,
     171             :                                           size_t *digest_length) {
     172           0 :   MOZ_ASSERT(cert);
     173             : 
     174             :   HASH_HashType ht;
     175             : 
     176           0 :   if (algorithm == "sha-1") {
     177           0 :     ht = HASH_AlgSHA1;
     178           0 :   } else if (algorithm == "sha-224") {
     179           0 :     ht = HASH_AlgSHA224;
     180           0 :   } else if (algorithm == "sha-256") {
     181           0 :     ht = HASH_AlgSHA256;
     182           0 :   } else if (algorithm == "sha-384") {
     183           0 :     ht = HASH_AlgSHA384;
     184           0 :   }  else if (algorithm == "sha-512") {
     185           0 :     ht = HASH_AlgSHA512;
     186             :   } else {
     187           0 :     return NS_ERROR_INVALID_ARG;
     188             :   }
     189             : 
     190           0 :   const SECHashObject *ho = HASH_GetHashObject(ht);
     191           0 :   MOZ_ASSERT(ho);
     192           0 :   if (!ho) {
     193           0 :     return NS_ERROR_INVALID_ARG;
     194             :   }
     195             : 
     196           0 :   MOZ_ASSERT(ho->length >= 20);  // Double check
     197             : 
     198           0 :   if (size < ho->length) {
     199           0 :     return NS_ERROR_INVALID_ARG;
     200             :   }
     201             : 
     202           0 :   SECStatus rv = HASH_HashBuf(ho->type, digest,
     203           0 :                               cert->derCert.data,
     204           0 :                               cert->derCert.len);
     205           0 :   if (rv != SECSuccess) {
     206           0 :     return NS_ERROR_FAILURE;
     207             :   }
     208             : 
     209           0 :   *digest_length = ho->length;
     210             : 
     211           0 :   return NS_OK;
     212             : }
     213             : 
     214           9 : }  // close namespace

Generated by: LCOV version 1.13