Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/mtransport/dtlsidentity.cpp
Line
Count
Source (jump to first uncovered line)
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
0
  }
26
0
27
0
  uint8_t random_name[16];
28
0
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
0
34
0
  std::string name;
35
0
  char chunk[3];
36
0
  for (unsigned char r_name : random_name) {
37
0
    SprintfLiteral(chunk, "%.2x", r_name);
38
0
    name += chunk;
39
0
  }
40
0
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
0
  }
46
0
47
0
  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
0
  }
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
0
58
0
  SECKEYPublicKey *pubkey;
59
0
  UniqueSECKEYPrivateKey private_key(
60
0
      PK11_GenerateKeyPair(slot.get(),
61
0
                           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
0
68
0
  UniqueCERTSubjectPublicKeyInfo spki(
69
0
      SECKEY_CreateSubjectPublicKeyInfo(public_key.get()));
70
0
  if (!spki) {
71
0
    return nullptr;
72
0
  }
73
0
74
0
  UniqueCERTCertificateRequest certreq(
75
0
      CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr));
76
0
  if (!certreq) {
77
0
    return nullptr;
78
0
  }
79
0
80
0
  // From 1 day before todayto 30 days after.
81
0
  // This is a sort of arbitrary range designed to be valid
82
0
  // now with some slack in case the other side expects
83
0
  // some before expiry.
84
0
  //
85
0
  // Note: explicit casts necessary to avoid
86
0
  //       warning C4307: '*' : integral constant overflow
87
0
  static const PRTime oneDay = PRTime(PR_USEC_PER_SEC)
88
0
                             * PRTime(60)  // sec
89
0
                             * PRTime(60)  // min
90
0
                             * PRTime(24); // hours
91
0
  PRTime now = PR_Now();
92
0
  PRTime notBefore = now - oneDay;
93
0
  PRTime notAfter = now + (PRTime(30) * oneDay);
94
0
95
0
  UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
96
0
  if (!validity) {
97
0
    return nullptr;
98
0
  }
99
0
100
0
  unsigned long serial;
101
0
  // Note: This serial in principle could collide, but it's unlikely
102
0
  rv = PK11_GenerateRandomOnSlot(slot.get(),
103
0
                                 reinterpret_cast<unsigned char *>(&serial),
104
0
                                 sizeof(serial));
105
0
  if (rv != SECSuccess) {
106
0
    return nullptr;
107
0
  }
108
0
109
0
  UniqueCERTCertificate certificate(
110
0
      CERT_CreateCertificate(serial, subject_name.get(), validity.get(),
111
0
                             certreq.get()));
112
0
  if (!certificate) {
113
0
    return nullptr;
114
0
  }
115
0
116
0
  PLArenaPool *arena = certificate->arena;
117
0
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
0
123
0
  // Set version to X509v3.
124
0
  *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3;
125
0
  certificate->version.len = 1;
126
0
127
0
  SECItem innerDER;
128
0
  innerDER.len = 0;
129
0
  innerDER.data = nullptr;
130
0
131
0
  if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(),
132
0
                          SEC_ASN1_GET(CERT_CertificateTemplate))) {
133
0
    return nullptr;
134
0
  }
135
0
136
0
  SECItem *signedCert = PORT_ArenaZNew(arena, SECItem);
137
0
  if (!signedCert) {
138
0
    return nullptr;
139
0
  }
140
0
141
0
  rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
142
0
                       private_key.get(),
143
0
                       SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
144
0
  if (rv != SECSuccess) {
145
0
    return nullptr;
146
0
  }
147
0
  certificate->derCert = *signedCert;
148
0
149
0
  RefPtr<DtlsIdentity> identity = new DtlsIdentity(std::move(private_key),
150
0
                                                   std::move(certificate),
151
0
                                                   ssl_kea_ecdh);
152
0
  return identity.forget();
153
0
}
154
155
const std::string DtlsIdentity::DEFAULT_HASH_ALGORITHM = "sha-256";
156
157
nsresult DtlsIdentity::ComputeFingerprint(const std::string algorithm,
158
                                          uint8_t *digest,
159
                                          size_t size,
160
0
                                          size_t *digest_length) const {
161
0
  const UniqueCERTCertificate& c = cert();
162
0
  MOZ_ASSERT(c);
163
0
164
0
  return ComputeFingerprint(c, algorithm, digest, size, digest_length);
165
0
}
166
167
nsresult DtlsIdentity::ComputeFingerprint(const UniqueCERTCertificate& cert,
168
                                          const std::string algorithm,
169
                                          uint8_t *digest,
170
                                          size_t size,
171
0
                                          size_t *digest_length) {
172
0
  MOZ_ASSERT(cert);
173
0
174
0
  HASH_HashType ht;
175
0
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
0
  } else {
187
0
    return NS_ERROR_INVALID_ARG;
188
0
  }
189
0
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
0
  }
195
0
196
0
  MOZ_ASSERT(ho->length >= 20);  // Double check
197
0
198
0
  if (size < ho->length) {
199
0
    return NS_ERROR_INVALID_ARG;
200
0
  }
201
0
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
0
  }
208
0
209
0
  *digest_length = ho->length;
210
0
211
0
  return NS_OK;
212
0
}
213
214
}  // close namespace