dtlsidentity.cpp 6.1 KB

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