/src/nss/lib/ssl/tls13subcerts.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
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 |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nss.h" |
8 | | #include "pk11func.h" |
9 | | #include "secder.h" |
10 | | #include "sechash.h" |
11 | | #include "ssl.h" |
12 | | #include "sslproto.h" |
13 | | #include "sslimpl.h" |
14 | | #include "ssl3exthandle.h" |
15 | | #include "tls13exthandle.h" |
16 | | #include "tls13hkdf.h" |
17 | | #include "tls13subcerts.h" |
18 | | |
19 | | /* Parses the delegated credential (DC) from the raw extension |b| of length |
20 | | * |length|. Memory for the DC is allocated and set to |*dcp|. |
21 | | * |
22 | | * It's the caller's responsibility to invoke |tls13_DestroyDelegatedCredential| |
23 | | * when this data is no longer needed. |
24 | | */ |
25 | | SECStatus |
26 | | tls13_ReadDelegatedCredential(PRUint8 *b, PRUint32 length, |
27 | | sslDelegatedCredential **dcp) |
28 | 0 | { |
29 | 0 | sslDelegatedCredential *dc = NULL; |
30 | 0 | SECStatus rv; |
31 | 0 | PRUint64 n; |
32 | 0 | sslReadBuffer tmp; |
33 | 0 | sslReader rdr = SSL_READER(b, length); |
34 | |
|
35 | 0 | PORT_Assert(!*dcp); |
36 | |
|
37 | 0 | dc = PORT_ZNew(sslDelegatedCredential); |
38 | 0 | if (!dc) { |
39 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
40 | 0 | goto loser; |
41 | 0 | } |
42 | | |
43 | | /* Read the valid_time field of DelegatedCredential.cred. */ |
44 | 0 | rv = sslRead_ReadNumber(&rdr, 4, &n); |
45 | 0 | if (rv != SECSuccess) { |
46 | 0 | goto loser; |
47 | 0 | } |
48 | 0 | dc->validTime = n; |
49 | | |
50 | | /* Read the expected_cert_verify_algorithm field of |
51 | | * DelegatedCredential.cred. */ |
52 | 0 | rv = sslRead_ReadNumber(&rdr, 2, &n); |
53 | 0 | if (rv != SECSuccess) { |
54 | 0 | goto loser; |
55 | 0 | } |
56 | 0 | dc->expectedCertVerifyAlg = n; |
57 | | |
58 | | /* Read the ASN1_subjectPublicKeyInfo field of DelegatedCredential.cred. */ |
59 | 0 | rv = sslRead_ReadVariable(&rdr, 3, &tmp); |
60 | 0 | if (rv != SECSuccess) { |
61 | 0 | goto loser; |
62 | 0 | } |
63 | 0 | rv = SECITEM_MakeItem(NULL, &dc->derSpki, tmp.buf, tmp.len); |
64 | 0 | if (rv != SECSuccess) { |
65 | 0 | goto loser; |
66 | 0 | } |
67 | | |
68 | | /* Parse the DER-encoded SubjectPublicKeyInfo. */ |
69 | 0 | dc->spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&dc->derSpki); |
70 | 0 | if (!dc->spki) { |
71 | 0 | goto loser; |
72 | 0 | } |
73 | | |
74 | | /* Read the algorithm field of the DelegatedCredential. */ |
75 | 0 | rv = sslRead_ReadNumber(&rdr, 2, &n); |
76 | 0 | if (rv != SECSuccess) { |
77 | 0 | goto loser; |
78 | 0 | } |
79 | 0 | dc->alg = n; |
80 | | |
81 | | /* Read the signature field of the DelegatedCredential. */ |
82 | 0 | rv = sslRead_ReadVariable(&rdr, 2, &tmp); |
83 | 0 | if (rv != SECSuccess) { |
84 | 0 | goto loser; |
85 | 0 | } |
86 | 0 | rv = SECITEM_MakeItem(NULL, &dc->signature, tmp.buf, tmp.len); |
87 | 0 | if (rv != SECSuccess) { |
88 | 0 | goto loser; |
89 | 0 | } |
90 | | |
91 | | /* There should be nothing left to read. */ |
92 | 0 | if (SSL_READER_REMAINING(&rdr) > 0) { |
93 | 0 | goto loser; |
94 | 0 | } |
95 | | |
96 | 0 | *dcp = dc; |
97 | 0 | return SECSuccess; |
98 | | |
99 | 0 | loser: |
100 | 0 | tls13_DestroyDelegatedCredential(dc); |
101 | 0 | *dcp = NULL; |
102 | 0 | return SECFailure; |
103 | 0 | } |
104 | | |
105 | | /* Frees |dc| from the heap. */ |
106 | | void |
107 | | tls13_DestroyDelegatedCredential(sslDelegatedCredential *dc) |
108 | 354k | { |
109 | 354k | if (!dc) { |
110 | 354k | return; |
111 | 354k | } |
112 | | |
113 | 0 | SECKEY_DestroySubjectPublicKeyInfo(dc->spki); |
114 | 0 | SECITEM_FreeItem(&dc->derSpki, PR_FALSE); |
115 | 0 | SECITEM_FreeItem(&dc->signature, PR_FALSE); |
116 | 0 | PORT_ZFree(dc, sizeof(sslDelegatedCredential)); |
117 | 0 | } |
118 | | |
119 | | /* Sets |*certVerifyAlg| to the expected_cert_verify_algorithm field from the |
120 | | * serialized DC |in|. Returns SECSuccess upon success; SECFailure indicates a |
121 | | * decoding failure or the input wasn't long enough. |
122 | | */ |
123 | | static SECStatus |
124 | | tls13_GetExpectedCertVerifyAlg(SECItem in, SSLSignatureScheme *certVerifyAlg) |
125 | 0 | { |
126 | 0 | SECStatus rv; |
127 | 0 | PRUint64 n; |
128 | 0 | sslReader rdr = SSL_READER(in.data, in.len); |
129 | |
|
130 | 0 | if (in.len < 6) { /* Buffer too short to contain the first two params. */ |
131 | 0 | return SECFailure; |
132 | 0 | } |
133 | | |
134 | 0 | rv = sslRead_ReadNumber(&rdr, 4, &n); |
135 | 0 | if (rv != SECSuccess) { |
136 | 0 | return SECFailure; |
137 | 0 | } |
138 | | |
139 | 0 | rv = sslRead_ReadNumber(&rdr, 2, &n); |
140 | 0 | if (rv != SECSuccess) { |
141 | 0 | return SECFailure; |
142 | 0 | } |
143 | 0 | *certVerifyAlg = n; |
144 | |
|
145 | 0 | return SECSuccess; |
146 | 0 | } |
147 | | |
148 | | /* Returns PR_TRUE if the host is verifying the handshake with a DC. */ |
149 | | PRBool |
150 | | tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss) |
151 | 0 | { |
152 | | /* We currently do not support client-delegated credentials. */ |
153 | 0 | if (ss->sec.isServer || |
154 | 0 | !ss->opt.enableDelegatedCredentials || |
155 | 0 | !ss->xtnData.peerDelegCred) { |
156 | 0 | return PR_FALSE; |
157 | 0 | } |
158 | | |
159 | 0 | return PR_TRUE; |
160 | 0 | } |
161 | | |
162 | | /* Returns PR_TRUE if the host is signing the handshake with a DC. */ |
163 | | PRBool |
164 | | tls13_IsSigningWithDelegatedCredential(const sslSocket *ss) |
165 | 2.40k | { |
166 | 2.40k | if (!ss->sec.isServer || |
167 | 2.40k | !ss->xtnData.sendingDelegCredToPeer || |
168 | 2.40k | !ss->xtnData.peerRequestedDelegCred) { |
169 | 2.40k | return PR_FALSE; |
170 | 2.40k | } |
171 | | |
172 | 0 | return PR_TRUE; |
173 | 2.40k | } |
174 | | |
175 | | /* Commits to authenticating with a DC if all of the following conditions hold: |
176 | | * - the negotiated protocol is TLS 1.3 or newer; |
177 | | * - the selected certificate has a DC configured; |
178 | | * - the peer has indicated support for this extension; |
179 | | * - the peer has indicated support for the DC signature scheme; and |
180 | | * - the host supports the DC signature scheme. |
181 | | * |
182 | | * It's the caller's responsibility to ensure that the version has been |
183 | | * negotiated and the certificate has been selected. |
184 | | */ |
185 | | SECStatus |
186 | | tls13_MaybeSetDelegatedCredential(sslSocket *ss) |
187 | 2.51k | { |
188 | 2.51k | SECStatus rv; |
189 | 2.51k | PRBool doesRsaPss; |
190 | 2.51k | SECKEYPrivateKey *priv; |
191 | 2.51k | SSLSignatureScheme scheme; |
192 | | |
193 | | /* Assert that the host is the server (we do not currently support |
194 | | * client-delegated credentials), the certificate has been |
195 | | * chosen, TLS 1.3 or higher has been negotiated, and that the set of |
196 | | * signature schemes supported by the client is known. |
197 | | */ |
198 | 2.51k | PORT_Assert(ss->sec.isServer); |
199 | 2.51k | PORT_Assert(ss->sec.serverCert); |
200 | 2.51k | PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); |
201 | 2.51k | PORT_Assert(ss->xtnData.peerRequestedDelegCred == !!ss->xtnData.delegCredSigSchemes); |
202 | | |
203 | | /* Check that the peer has indicated support and that a DC has been |
204 | | * configured for the selected certificate. |
205 | | */ |
206 | 2.51k | if (!ss->xtnData.peerRequestedDelegCred || |
207 | 2.51k | !ss->xtnData.delegCredSigSchemes || |
208 | 2.51k | !ss->sec.serverCert->delegCred.len || |
209 | 2.51k | !ss->sec.serverCert->delegCredKeyPair) { |
210 | 2.51k | return SECSuccess; |
211 | 2.51k | } |
212 | | |
213 | | /* Check that the host and peer both support the signing algorithm used with |
214 | | * the DC. |
215 | | */ |
216 | 0 | rv = tls13_GetExpectedCertVerifyAlg(ss->sec.serverCert->delegCred, |
217 | 0 | &scheme); |
218 | 0 | if (rv != SECSuccess) { |
219 | 0 | return SECFailure; |
220 | 0 | } |
221 | | |
222 | 0 | priv = ss->sec.serverCert->delegCredKeyPair->privKey; |
223 | 0 | rv = ssl_PrivateKeySupportsRsaPss(priv, NULL, NULL, &doesRsaPss); |
224 | 0 | if (rv != SECSuccess) { |
225 | 0 | return SECFailure; |
226 | 0 | } |
227 | | |
228 | 0 | if (!ssl_SignatureSchemeEnabled(ss, scheme) || |
229 | 0 | !ssl_CanUseSignatureScheme(scheme, |
230 | 0 | ss->xtnData.delegCredSigSchemes, |
231 | 0 | ss->xtnData.numDelegCredSigSchemes, |
232 | 0 | PR_FALSE /* requireSha1 */, |
233 | 0 | doesRsaPss)) { |
234 | 0 | return SECSuccess; |
235 | 0 | } |
236 | | |
237 | | /* Commit to sending a DC and set the handshake signature scheme to the |
238 | | * indicated algorithm. |
239 | | */ |
240 | 0 | ss->xtnData.sendingDelegCredToPeer = PR_TRUE; |
241 | 0 | ss->ssl3.hs.signatureScheme = scheme; |
242 | 0 | return SECSuccess; |
243 | 0 | } |
244 | | |
245 | | /* Serializes the DC up to the signature. */ |
246 | | static SECStatus |
247 | | tls13_AppendCredentialParams(sslBuffer *buf, sslDelegatedCredential *dc) |
248 | 0 | { |
249 | 0 | SECStatus rv; |
250 | 0 | rv = sslBuffer_AppendNumber(buf, dc->validTime, 4); |
251 | 0 | if (rv != SECSuccess) { |
252 | 0 | return SECFailure; /* Error set by caller. */ |
253 | 0 | } |
254 | | |
255 | 0 | rv = sslBuffer_AppendNumber(buf, dc->expectedCertVerifyAlg, 2); |
256 | 0 | if (rv != SECSuccess) { |
257 | 0 | return SECFailure; |
258 | 0 | } |
259 | | |
260 | 0 | rv = sslBuffer_AppendVariable(buf, dc->derSpki.data, dc->derSpki.len, 3); |
261 | 0 | if (rv != SECSuccess) { |
262 | 0 | return SECFailure; |
263 | 0 | } |
264 | | |
265 | 0 | rv = sslBuffer_AppendNumber(buf, dc->alg, 2); |
266 | 0 | if (rv != SECSuccess) { |
267 | 0 | return SECFailure; |
268 | 0 | } |
269 | | |
270 | 0 | return SECSuccess; |
271 | 0 | } |
272 | | |
273 | | /* Serializes the DC signature. */ |
274 | | static SECStatus |
275 | | tls13_AppendCredentialSignature(sslBuffer *buf, sslDelegatedCredential *dc) |
276 | 0 | { |
277 | 0 | SECStatus rv; |
278 | 0 | rv = sslBuffer_AppendVariable(buf, dc->signature.data, |
279 | 0 | dc->signature.len, 2); |
280 | 0 | if (rv != SECSuccess) { |
281 | 0 | return SECFailure; |
282 | 0 | } |
283 | | |
284 | 0 | return SECSuccess; |
285 | 0 | } |
286 | | |
287 | | /* Hashes the message used to sign/verify the DC. */ |
288 | | static SECStatus |
289 | | tls13_HashCredentialSignatureMessage(SSL3Hashes *hash, |
290 | | SSLSignatureScheme scheme, |
291 | | const CERTCertificate *cert, |
292 | | const sslBuffer *dcBuf) |
293 | 0 | { |
294 | 0 | SECStatus rv; |
295 | 0 | PK11Context *ctx = NULL; |
296 | 0 | unsigned int hashLen; |
297 | | |
298 | | /* Set up hash context. */ |
299 | 0 | hash->hashAlg = ssl_SignatureSchemeToHashType(scheme); |
300 | 0 | ctx = PK11_CreateDigestContext(ssl3_HashTypeToOID(hash->hashAlg)); |
301 | 0 | if (!ctx) { |
302 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
303 | 0 | goto loser; |
304 | 0 | } |
305 | | |
306 | 0 | static const PRUint8 kCtxStrPadding[64] = { |
307 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
308 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
309 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
310 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
311 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
312 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
313 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
314 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 |
315 | 0 | }; |
316 | |
|
317 | 0 | static const PRUint8 kCtxStr[] = "TLS, server delegated credentials"; |
318 | | |
319 | | /* Hash the message signed by the peer. */ |
320 | 0 | rv = SECSuccess; |
321 | 0 | rv |= PK11_DigestBegin(ctx); |
322 | 0 | rv |= PK11_DigestOp(ctx, kCtxStrPadding, sizeof kCtxStrPadding); |
323 | 0 | rv |= PK11_DigestOp(ctx, kCtxStr, 1 /* 0-byte */ + strlen((const char *)kCtxStr)); |
324 | 0 | rv |= PK11_DigestOp(ctx, cert->derCert.data, cert->derCert.len); |
325 | 0 | rv |= PK11_DigestOp(ctx, dcBuf->buf, dcBuf->len); |
326 | 0 | rv |= PK11_DigestFinal(ctx, hash->u.raw, &hashLen, sizeof hash->u.raw); |
327 | 0 | if (rv != SECSuccess) { |
328 | 0 | PORT_SetError(SSL_ERROR_SHA_DIGEST_FAILURE); |
329 | 0 | goto loser; |
330 | 0 | } |
331 | | |
332 | 0 | hash->len = hashLen; |
333 | 0 | if (ctx) { |
334 | 0 | PK11_DestroyContext(ctx, PR_TRUE); |
335 | 0 | } |
336 | 0 | return SECSuccess; |
337 | | |
338 | 0 | loser: |
339 | 0 | if (ctx) { |
340 | 0 | PK11_DestroyContext(ctx, PR_TRUE); |
341 | 0 | } |
342 | 0 | return SECFailure; |
343 | 0 | } |
344 | | |
345 | | /* Verifies the DC signature. */ |
346 | | static SECStatus |
347 | | tls13_VerifyCredentialSignature(sslSocket *ss, sslDelegatedCredential *dc) |
348 | 0 | { |
349 | 0 | SECStatus rv = SECSuccess; |
350 | 0 | SSL3Hashes hash; |
351 | 0 | sslBuffer dcBuf = SSL_BUFFER_EMPTY; |
352 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
353 | 0 | SECKEYPublicKey *pubKey = NULL; |
354 | | |
355 | | /* Serialize the DC parameters. */ |
356 | 0 | rv = tls13_AppendCredentialParams(&dcBuf, dc); |
357 | 0 | if (rv != SECSuccess) { |
358 | 0 | goto loser; /* Error set by caller. */ |
359 | 0 | } |
360 | | |
361 | | /* Hash the message that was signed by the delegator. */ |
362 | 0 | rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf); |
363 | 0 | if (rv != SECSuccess) { |
364 | 0 | FATAL_ERROR(ss, PORT_GetError(), internal_error); |
365 | 0 | goto loser; |
366 | 0 | } |
367 | | |
368 | 0 | pubKey = SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo); |
369 | 0 | if (pubKey == NULL) { |
370 | 0 | FATAL_ERROR(ss, SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE, internal_error); |
371 | 0 | goto loser; |
372 | 0 | } |
373 | | |
374 | | /* Verify the signature of the message. */ |
375 | 0 | rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, dc->alg, |
376 | 0 | &hash, &dc->signature); |
377 | 0 | if (rv != SECSuccess) { |
378 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_BAD_SIGNATURE, illegal_parameter); |
379 | 0 | goto loser; |
380 | 0 | } |
381 | | |
382 | 0 | SECOidTag spkiAlg = SECOID_GetAlgorithmTag(&(dc->spki->algorithm)); |
383 | 0 | if (spkiAlg == SEC_OID_PKCS1_RSA_ENCRYPTION) { |
384 | 0 | FATAL_ERROR(ss, SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, illegal_parameter); |
385 | 0 | goto loser; |
386 | 0 | } |
387 | | |
388 | 0 | SECKEY_DestroyPublicKey(pubKey); |
389 | 0 | sslBuffer_Clear(&dcBuf); |
390 | 0 | return SECSuccess; |
391 | | |
392 | 0 | loser: |
393 | 0 | SECKEY_DestroyPublicKey(pubKey); |
394 | 0 | sslBuffer_Clear(&dcBuf); |
395 | 0 | return SECFailure; |
396 | 0 | } |
397 | | |
398 | | /* Checks that the peer's end-entity certificate has the correct key usage. */ |
399 | | static SECStatus |
400 | | tls13_CheckCertDelegationUsage(sslSocket *ss) |
401 | 0 | { |
402 | 0 | int i; |
403 | 0 | PRBool found; |
404 | 0 | CERTCertExtension *ext; |
405 | 0 | SECItem delegUsageOid = { siBuffer, NULL, 0 }; |
406 | 0 | const CERTCertificate *cert = ss->sec.peerCert; |
407 | | |
408 | | /* 1.3.6.1.4.1.44363.44, as defined in draft-ietf-tls-subcerts. */ |
409 | 0 | static unsigned char kDelegationUsageOid[] = { |
410 | 0 | 0x2b, |
411 | 0 | 0x06, |
412 | 0 | 0x01, |
413 | 0 | 0x04, |
414 | 0 | 0x01, |
415 | 0 | 0x82, |
416 | 0 | 0xda, |
417 | 0 | 0x4b, |
418 | 0 | 0x2c |
419 | 0 | }; |
420 | |
|
421 | 0 | delegUsageOid.data = kDelegationUsageOid; |
422 | 0 | delegUsageOid.len = sizeof kDelegationUsageOid; |
423 | | |
424 | | /* The certificate must have the delegationUsage extension that authorizes |
425 | | * it to negotiate delegated credentials. |
426 | | */ |
427 | 0 | found = PR_FALSE; |
428 | 0 | for (i = 0; cert->extensions[i] != NULL; i++) { |
429 | 0 | ext = cert->extensions[i]; |
430 | 0 | if (SECITEM_CompareItem(&ext->id, &delegUsageOid) == SECEqual) { |
431 | 0 | found = PR_TRUE; |
432 | 0 | break; |
433 | 0 | } |
434 | 0 | } |
435 | | |
436 | | /* The certificate must also have the digitalSignature keyUsage set. */ |
437 | 0 | if (!found || |
438 | 0 | !cert->keyUsagePresent || |
439 | 0 | !(cert->keyUsage & KU_DIGITAL_SIGNATURE)) { |
440 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_INVALID_KEY_USAGE, illegal_parameter); |
441 | 0 | return SECFailure; |
442 | 0 | } |
443 | | |
444 | 0 | return SECSuccess; |
445 | 0 | } |
446 | | |
447 | | static SECStatus |
448 | | tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc) |
449 | 0 | { |
450 | 0 | SECStatus rv; |
451 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
452 | | /* 7 days in microseconds */ |
453 | 0 | static const PRTime kMaxDcValidity = ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC); |
454 | 0 | PRTime start, now, end; /* microseconds */ |
455 | |
|
456 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
457 | 0 | if (rv != SECSuccess) { |
458 | 0 | FATAL_ERROR(ss, PORT_GetError(), internal_error); |
459 | 0 | return SECFailure; |
460 | 0 | } |
461 | | |
462 | 0 | end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC); |
463 | 0 | now = ssl_Time(ss); |
464 | 0 | if (now > end || end < 0) { |
465 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter); |
466 | 0 | return SECFailure; |
467 | 0 | } |
468 | | |
469 | | /* Not more than 7 days remaining in the validity period. */ |
470 | 0 | if (end - now > kMaxDcValidity) { |
471 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, illegal_parameter); |
472 | 0 | return SECFailure; |
473 | 0 | } |
474 | | |
475 | 0 | return SECSuccess; |
476 | 0 | } |
477 | | |
478 | | /* Returns SECSucces if |dc| is a DC for the current handshake; otherwise it |
479 | | * returns SECFailure. A valid DC meets three requirements: (1) the signature |
480 | | * was produced by the peer's end-entity certificate, (2) the end-entity |
481 | | * certificate must have the correct key usage, and (3) the DC must not be |
482 | | * expired and its remaining TTL must be <= the maximum validity period (fixed |
483 | | * as 7 days). |
484 | | * |
485 | | * This function calls FATAL_ERROR() when an error occurs. |
486 | | */ |
487 | | SECStatus |
488 | | tls13_VerifyDelegatedCredential(sslSocket *ss, |
489 | | sslDelegatedCredential *dc) |
490 | 0 | { |
491 | 0 | SECStatus rv; |
492 | 0 | PRTime start; |
493 | 0 | PRExplodedTime end; |
494 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
495 | 0 | char endStr[256]; |
496 | |
|
497 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
498 | 0 | if (rv != SECSuccess) { |
499 | 0 | FATAL_ERROR(ss, PORT_GetError(), internal_error); |
500 | 0 | return SECFailure; |
501 | 0 | } |
502 | | |
503 | 0 | PR_ExplodeTime(start + (dc->validTime * PR_USEC_PER_SEC), |
504 | 0 | PR_GMTParameters, &end); |
505 | 0 | if (PR_FormatTime(endStr, sizeof(endStr), "%a %b %d %H:%M:%S %Y", &end)) { |
506 | 0 | SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential (expires %s)", |
507 | 0 | SSL_GETPID(), ss->fd, endStr)); |
508 | 0 | } else { |
509 | 0 | SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential", |
510 | 0 | SSL_GETPID(), ss->fd)); |
511 | 0 | } |
512 | |
|
513 | 0 | rv = SECSuccess; |
514 | 0 | rv |= tls13_VerifyCredentialSignature(ss, dc); |
515 | 0 | rv |= tls13_CheckCertDelegationUsage(ss); |
516 | 0 | rv |= tls13_CheckCredentialExpiration(ss, dc); |
517 | 0 | return rv; |
518 | 0 | } |
519 | | |
520 | | static CERTSubjectPublicKeyInfo * |
521 | | tls13_MakePssSpki(const SECKEYPublicKey *pub, SECOidTag hashOid) |
522 | 0 | { |
523 | 0 | SECStatus rv; |
524 | 0 | PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
525 | 0 | if (!arena) { |
526 | 0 | goto loser; /* Code already set. */ |
527 | 0 | } |
528 | 0 | CERTSubjectPublicKeyInfo *spki = PORT_ArenaZNew(arena, CERTSubjectPublicKeyInfo); |
529 | 0 | if (!spki) { |
530 | 0 | goto loser; /* Code already set. */ |
531 | 0 | } |
532 | 0 | spki->arena = arena; |
533 | |
|
534 | 0 | SECKEYRSAPSSParams params = { 0 }; |
535 | 0 | params.hashAlg = PORT_ArenaZNew(arena, SECAlgorithmID); |
536 | 0 | rv = SECOID_SetAlgorithmID(arena, params.hashAlg, hashOid, NULL); |
537 | 0 | if (rv != SECSuccess) { |
538 | 0 | goto loser; /* Code already set. */ |
539 | 0 | } |
540 | | |
541 | | /* Set the mask hash algorithm too, which is an argument to |
542 | | * a SEC_OID_PKCS1_MGF1 value. */ |
543 | 0 | SECAlgorithmID maskHashAlg; |
544 | 0 | memset(&maskHashAlg, 0, sizeof(maskHashAlg)); |
545 | 0 | rv = SECOID_SetAlgorithmID(arena, &maskHashAlg, hashOid, NULL); |
546 | 0 | if (rv != SECSuccess) { |
547 | 0 | goto loser; /* Code already set. */ |
548 | 0 | } |
549 | 0 | SECItem *maskHashAlgItem = |
550 | 0 | SEC_ASN1EncodeItem(arena, NULL, &maskHashAlg, |
551 | 0 | SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); |
552 | 0 | if (!maskHashAlgItem) { |
553 | | /* Probably OOM, but not certain. */ |
554 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
555 | 0 | goto loser; |
556 | 0 | } |
557 | | |
558 | 0 | params.maskAlg = PORT_ArenaZNew(arena, SECAlgorithmID); |
559 | 0 | rv = SECOID_SetAlgorithmID(arena, params.maskAlg, SEC_OID_PKCS1_MGF1, |
560 | 0 | maskHashAlgItem); |
561 | 0 | if (rv != SECSuccess) { |
562 | 0 | goto loser; /* Code already set. */ |
563 | 0 | } |
564 | | |
565 | | /* Always include saltLength: all hashes are larger than 20. */ |
566 | 0 | unsigned int saltLength = HASH_ResultLenByOidTag(hashOid); |
567 | 0 | PORT_Assert(saltLength > 20); |
568 | 0 | if (!SEC_ASN1EncodeInteger(arena, ¶ms.saltLength, saltLength)) { |
569 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
570 | 0 | goto loser; |
571 | 0 | } |
572 | | /* Omit the trailerField always. */ |
573 | | |
574 | 0 | SECItem *algorithmItem = |
575 | 0 | SEC_ASN1EncodeItem(arena, NULL, ¶ms, |
576 | 0 | SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); |
577 | 0 | if (!algorithmItem) { |
578 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
579 | 0 | goto loser; /* Code already set. */ |
580 | 0 | } |
581 | 0 | rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, |
582 | 0 | SEC_OID_PKCS1_RSA_PSS_SIGNATURE, algorithmItem); |
583 | 0 | if (rv != SECSuccess) { |
584 | 0 | goto loser; /* Code already set. */ |
585 | 0 | } |
586 | | |
587 | 0 | SECItem *pubItem = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, pub, |
588 | 0 | SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate)); |
589 | 0 | if (!pubItem) { |
590 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
591 | 0 | goto loser; |
592 | 0 | } |
593 | 0 | spki->subjectPublicKey.len *= 8; /* Key length is in bits. */ |
594 | 0 | return spki; |
595 | | |
596 | 0 | loser: |
597 | 0 | PORT_FreeArena(arena, PR_FALSE); |
598 | 0 | return NULL; |
599 | 0 | } |
600 | | |
601 | | static CERTSubjectPublicKeyInfo * |
602 | | tls13_MakeDcSpki(const SECKEYPublicKey *dcPub, SSLSignatureScheme dcCertVerifyAlg) |
603 | 0 | { |
604 | 0 | switch (SECKEY_GetPublicKeyType(dcPub)) { |
605 | 0 | case rsaKey: { |
606 | 0 | SECOidTag hashOid; |
607 | 0 | switch (dcCertVerifyAlg) { |
608 | | /* Note: RSAE schemes are NOT permitted within DC SPKIs. However, |
609 | | * support for their issuance remains so as to enable negative |
610 | | * testing of client behavior. */ |
611 | 0 | case ssl_sig_rsa_pss_rsae_sha256: |
612 | 0 | case ssl_sig_rsa_pss_rsae_sha384: |
613 | 0 | case ssl_sig_rsa_pss_rsae_sha512: |
614 | 0 | return SECKEY_CreateSubjectPublicKeyInfo(dcPub); |
615 | 0 | case ssl_sig_rsa_pss_pss_sha256: |
616 | 0 | hashOid = SEC_OID_SHA256; |
617 | 0 | break; |
618 | 0 | case ssl_sig_rsa_pss_pss_sha384: |
619 | 0 | hashOid = SEC_OID_SHA384; |
620 | 0 | break; |
621 | 0 | case ssl_sig_rsa_pss_pss_sha512: |
622 | 0 | hashOid = SEC_OID_SHA512; |
623 | 0 | break; |
624 | | |
625 | 0 | default: |
626 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
627 | 0 | return NULL; |
628 | 0 | } |
629 | 0 | return tls13_MakePssSpki(dcPub, hashOid); |
630 | 0 | } |
631 | | |
632 | 0 | case ecKey: { |
633 | 0 | const sslNamedGroupDef *group = ssl_ECPubKey2NamedGroup(dcPub); |
634 | 0 | if (!group) { |
635 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
636 | 0 | return NULL; |
637 | 0 | } |
638 | 0 | SSLSignatureScheme keyScheme; |
639 | 0 | switch (group->name) { |
640 | 0 | case ssl_grp_ec_secp256r1: |
641 | 0 | keyScheme = ssl_sig_ecdsa_secp256r1_sha256; |
642 | 0 | break; |
643 | 0 | case ssl_grp_ec_secp384r1: |
644 | 0 | keyScheme = ssl_sig_ecdsa_secp384r1_sha384; |
645 | 0 | break; |
646 | 0 | case ssl_grp_ec_secp521r1: |
647 | 0 | keyScheme = ssl_sig_ecdsa_secp521r1_sha512; |
648 | 0 | break; |
649 | 0 | default: |
650 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
651 | 0 | return NULL; |
652 | 0 | } |
653 | 0 | if (keyScheme != dcCertVerifyAlg) { |
654 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
655 | 0 | return NULL; |
656 | 0 | } |
657 | 0 | return SECKEY_CreateSubjectPublicKeyInfo(dcPub); |
658 | 0 | } |
659 | | |
660 | 0 | default: |
661 | 0 | break; |
662 | 0 | } |
663 | | |
664 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
665 | 0 | return NULL; |
666 | 0 | } |
667 | | |
668 | | /* Returns a serialized DC with the given parameters. |
669 | | * |
670 | | * Note that this function is meant primarily for testing. In particular, it |
671 | | * DOES NOT verify any of the following: |
672 | | * - |certPriv| is the private key corresponding to |cert|; |
673 | | * - that |checkCertKeyUsage(cert) == SECSuccess|; |
674 | | * - |dcValidFor| is less than 7 days (the maximum permitted by the spec); or |
675 | | * - validTime doesn't overflow a PRUint32. |
676 | | * |
677 | | * These conditions are things we want to test for, which is why we allow them |
678 | | * here. A real API for creating DCs would want to explicitly check ALL of these |
679 | | * conditions are met. |
680 | | */ |
681 | | SECStatus |
682 | | SSLExp_DelegateCredential(const CERTCertificate *cert, |
683 | | const SECKEYPrivateKey *certPriv, |
684 | | const SECKEYPublicKey *dcPub, |
685 | | SSLSignatureScheme dcCertVerifyAlg, |
686 | | PRUint32 dcValidFor, |
687 | | PRTime now, |
688 | | SECItem *out) |
689 | 0 | { |
690 | 0 | SECStatus rv; |
691 | 0 | SSL3Hashes hash; |
692 | 0 | CERTSubjectPublicKeyInfo *spki = NULL; |
693 | 0 | SECKEYPrivateKey *tmpPriv = NULL; |
694 | 0 | sslDelegatedCredential *dc = NULL; |
695 | 0 | sslBuffer dcBuf = SSL_BUFFER_EMPTY; |
696 | |
|
697 | 0 | if (!cert || !certPriv || !dcPub || !out) { |
698 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
699 | 0 | return SECFailure; |
700 | 0 | } |
701 | | |
702 | 0 | dc = PORT_ZNew(sslDelegatedCredential); |
703 | 0 | if (!dc) { |
704 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
705 | 0 | goto loser; |
706 | 0 | } |
707 | | |
708 | | /* Serialize the DC parameters. */ |
709 | 0 | PRTime start; |
710 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
711 | 0 | if (rv != SECSuccess) { |
712 | 0 | goto loser; |
713 | 0 | } |
714 | 0 | dc->validTime = ((now - start) / PR_USEC_PER_SEC) + dcValidFor; |
715 | | |
716 | | /* Building the SPKI also validates |dcCertVerifyAlg|. */ |
717 | 0 | spki = tls13_MakeDcSpki(dcPub, dcCertVerifyAlg); |
718 | 0 | if (!spki) { |
719 | 0 | goto loser; |
720 | 0 | } |
721 | 0 | dc->expectedCertVerifyAlg = dcCertVerifyAlg; |
722 | |
|
723 | 0 | SECItem *spkiDer = |
724 | 0 | SEC_ASN1EncodeItem(NULL /*arena*/, &dc->derSpki, spki, |
725 | 0 | SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate)); |
726 | 0 | if (!spkiDer) { |
727 | 0 | goto loser; |
728 | 0 | } |
729 | | |
730 | 0 | rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, |
731 | 0 | PR_TRUE /* isTls13 */, &dc->alg); |
732 | 0 | if (rv != SECSuccess) { |
733 | 0 | goto loser; |
734 | 0 | } |
735 | | |
736 | 0 | if (dc->alg == ssl_sig_none) { |
737 | 0 | SECOidTag spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); |
738 | | /* If the Cert SPKI contained an AlgorithmIdentifier of "rsaEncryption", set a |
739 | | * default rsa_pss_rsae_sha256 scheme. NOTE: RSAE SPKIs are not permitted within |
740 | | * "real" Delegated Credentials. However, since this function is primarily used for |
741 | | * testing, we retain this support in order to verify that these DCs are rejected |
742 | | * by tls13_VerifyDelegatedCredential. */ |
743 | 0 | if (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION) { |
744 | 0 | SSLSignatureScheme scheme = ssl_sig_rsa_pss_rsae_sha256; |
745 | 0 | if (ssl_SignatureSchemeValid(scheme, spkiOid, PR_TRUE /* isTls13 */)) { |
746 | 0 | dc->alg = scheme; |
747 | 0 | } |
748 | 0 | } |
749 | 0 | } |
750 | 0 | PORT_Assert(dc->alg != ssl_sig_none); |
751 | |
|
752 | 0 | rv = tls13_AppendCredentialParams(&dcBuf, dc); |
753 | 0 | if (rv != SECSuccess) { |
754 | 0 | goto loser; |
755 | 0 | } |
756 | | |
757 | | /* Hash signature message. */ |
758 | 0 | rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf); |
759 | 0 | if (rv != SECSuccess) { |
760 | 0 | goto loser; |
761 | 0 | } |
762 | | |
763 | | /* Sign the hash with the delegation key. |
764 | | * |
765 | | * The PK11 API discards const qualifiers, so we have to make a copy of |
766 | | * |certPriv| and pass the copy to |ssl3_SignHashesWithPrivKey|. |
767 | | */ |
768 | 0 | tmpPriv = SECKEY_CopyPrivateKey(certPriv); |
769 | 0 | rv = ssl3_SignHashesWithPrivKey(&hash, tmpPriv, dc->alg, |
770 | 0 | PR_TRUE /* isTls */, &dc->signature); |
771 | 0 | if (rv != SECSuccess) { |
772 | 0 | goto loser; |
773 | 0 | } |
774 | | |
775 | | /* Serialize the DC signature. */ |
776 | 0 | rv = tls13_AppendCredentialSignature(&dcBuf, dc); |
777 | 0 | if (rv != SECSuccess) { |
778 | 0 | goto loser; |
779 | 0 | } |
780 | | |
781 | | /* Copy the serialized DC to |out|. */ |
782 | 0 | rv = SECITEM_MakeItem(NULL, out, dcBuf.buf, dcBuf.len); |
783 | 0 | if (rv != SECSuccess) { |
784 | 0 | goto loser; |
785 | 0 | } |
786 | | |
787 | 0 | PRINT_BUF(20, (NULL, "delegated credential", dcBuf.buf, dcBuf.len)); |
788 | |
|
789 | 0 | SECKEY_DestroySubjectPublicKeyInfo(spki); |
790 | 0 | SECKEY_DestroyPrivateKey(tmpPriv); |
791 | 0 | tls13_DestroyDelegatedCredential(dc); |
792 | 0 | sslBuffer_Clear(&dcBuf); |
793 | 0 | return SECSuccess; |
794 | | |
795 | 0 | loser: |
796 | 0 | SECKEY_DestroySubjectPublicKeyInfo(spki); |
797 | 0 | SECKEY_DestroyPrivateKey(tmpPriv); |
798 | 0 | tls13_DestroyDelegatedCredential(dc); |
799 | 0 | sslBuffer_Clear(&dcBuf); |
800 | 0 | return SECFailure; |
801 | 0 | } |