/src/nss/lib/ssl/tls13subcerts.c
Line | Count | Source |
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.72k | { |
166 | 2.72k | if (!ss->sec.isServer || |
167 | 2.72k | !ss->xtnData.sendingDelegCredToPeer || |
168 | 2.72k | !ss->xtnData.peerRequestedDelegCred) { |
169 | 2.72k | return PR_FALSE; |
170 | 2.72k | } |
171 | | |
172 | 0 | return PR_TRUE; |
173 | 2.72k | } |
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.85k | { |
188 | 2.85k | SECStatus rv; |
189 | 2.85k | PRBool doesRsaPss; |
190 | 2.85k | SECKEYPrivateKey *priv; |
191 | 2.85k | 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.85k | PORT_Assert(ss->sec.isServer); |
199 | 2.85k | PORT_Assert(ss->sec.serverCert); |
200 | 2.85k | PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); |
201 | 2.85k | 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.85k | if (!ss->xtnData.peerRequestedDelegCred || |
207 | 10 | !ss->xtnData.delegCredSigSchemes || |
208 | 10 | !ss->sec.serverCert->delegCred.len || |
209 | 2.85k | !ss->sec.serverCert->delegCredKeyPair) { |
210 | 2.85k | return SECSuccess; |
211 | 2.85k | } |
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_HashCredentialAndSignOrVerifyMessage(SECKEYPrivateKey *privKey, |
290 | | SECKEYPublicKey *pubKey, |
291 | | SSLSignatureScheme scheme, |
292 | | sslSignOrVerify direction, |
293 | | const CERTCertificate *cert, |
294 | | const sslBuffer *dcBuf, |
295 | | SECItem *signature, void *pwArg) |
296 | 0 | { |
297 | 0 | SECStatus rv; |
298 | 0 | tlsSignOrVerifyContext ctx; |
299 | | |
300 | | /* Set up sign and hash context. */ |
301 | 0 | ctx = tls_CreateSignOrVerifyContext(privKey, pubKey, scheme, direction, |
302 | 0 | signature, pwArg); |
303 | 0 | if (!ctx.u.ptr) { |
304 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
305 | 0 | goto loser; |
306 | 0 | } |
307 | | |
308 | 0 | const PRUint8 kCtxStrPadding[64] = { |
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 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
316 | 0 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 |
317 | 0 | }; |
318 | |
|
319 | 0 | const PRUint8 kCtxStr[] = "TLS, server delegated credentials"; |
320 | | |
321 | | /* Hash the message signed by the peer. */ |
322 | 0 | rv = tls_SignOrVerifyUpdate(ctx, kCtxStrPadding, sizeof kCtxStrPadding); |
323 | 0 | if (rv != SECSuccess) |
324 | 0 | goto loser; |
325 | | /* sizeof kCtxStr includes the null terminator, which serves as the 0x00 |
326 | | * separator specified in RFC 9345 section 4. */ |
327 | 0 | rv = tls_SignOrVerifyUpdate(ctx, kCtxStr, sizeof kCtxStr); |
328 | 0 | if (rv != SECSuccess) |
329 | 0 | goto loser; |
330 | 0 | rv = tls_SignOrVerifyUpdate(ctx, cert->derCert.data, cert->derCert.len); |
331 | 0 | if (rv != SECSuccess) |
332 | 0 | goto loser; |
333 | 0 | rv = tls_SignOrVerifyUpdate(ctx, dcBuf->buf, dcBuf->len); |
334 | 0 | if (rv != SECSuccess) |
335 | 0 | goto loser; |
336 | 0 | rv = tls_SignOrVerifyEnd(ctx, signature); |
337 | 0 | if (rv != SECSuccess) |
338 | 0 | goto loser; |
339 | | |
340 | 0 | return SECSuccess; |
341 | | |
342 | 0 | loser: |
343 | 0 | tls_DestroySignOrVerifyContext(&ctx); |
344 | 0 | return SECFailure; |
345 | 0 | } |
346 | | |
347 | | /* Verifies the DC signature. */ |
348 | | static SECStatus |
349 | | tls13_VerifyCredentialSignature(sslSocket *ss, sslDelegatedCredential *dc) |
350 | 0 | { |
351 | 0 | SECStatus rv = SECSuccess; |
352 | 0 | sslBuffer dcBuf = SSL_BUFFER_EMPTY; |
353 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
354 | 0 | SECKEYPublicKey *pubKey = NULL; |
355 | 0 | void *pwArg = ss->pkcs11PinArg; |
356 | | |
357 | | /* Serialize the DC parameters. */ |
358 | 0 | rv = tls13_AppendCredentialParams(&dcBuf, dc); |
359 | 0 | if (rv != SECSuccess) { |
360 | 0 | goto loser; /* Error set by caller. */ |
361 | 0 | } |
362 | | |
363 | 0 | pubKey = SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo); |
364 | 0 | if (pubKey == NULL) { |
365 | 0 | FATAL_ERROR(ss, SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE, internal_error); |
366 | 0 | goto loser; |
367 | 0 | } |
368 | | |
369 | | /* Verify the signature of the delegatormessage. */ |
370 | 0 | rv = tls13_HashCredentialAndSignOrVerifyMessage(NULL, pubKey, dc->alg, |
371 | 0 | sig_verify, cert, &dcBuf, |
372 | 0 | &dc->signature, pwArg); |
373 | 0 | if (rv != SECSuccess) { |
374 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_BAD_SIGNATURE, illegal_parameter); |
375 | 0 | goto loser; |
376 | 0 | } |
377 | | |
378 | 0 | SECOidTag spkiAlg = SECOID_GetAlgorithmTag(&(dc->spki->algorithm)); |
379 | 0 | if (spkiAlg == SEC_OID_PKCS1_RSA_ENCRYPTION) { |
380 | 0 | FATAL_ERROR(ss, SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, illegal_parameter); |
381 | 0 | goto loser; |
382 | 0 | } |
383 | | |
384 | 0 | SECKEY_DestroyPublicKey(pubKey); |
385 | 0 | sslBuffer_Clear(&dcBuf); |
386 | 0 | return SECSuccess; |
387 | | |
388 | 0 | loser: |
389 | 0 | SECKEY_DestroyPublicKey(pubKey); |
390 | 0 | sslBuffer_Clear(&dcBuf); |
391 | 0 | return SECFailure; |
392 | 0 | } |
393 | | |
394 | | /* Checks that the peer's end-entity certificate has the correct key usage. */ |
395 | | static SECStatus |
396 | | tls13_CheckCertDelegationUsage(sslSocket *ss) |
397 | 0 | { |
398 | 0 | int i; |
399 | 0 | PRBool found; |
400 | 0 | CERTCertExtension *ext; |
401 | 0 | SECItem delegUsageOid = { siBuffer, NULL, 0 }; |
402 | 0 | const CERTCertificate *cert = ss->sec.peerCert; |
403 | | |
404 | | /* 1.3.6.1.4.1.44363.44, as defined in draft-ietf-tls-subcerts. */ |
405 | 0 | static unsigned char kDelegationUsageOid[] = { |
406 | 0 | 0x2b, |
407 | 0 | 0x06, |
408 | 0 | 0x01, |
409 | 0 | 0x04, |
410 | 0 | 0x01, |
411 | 0 | 0x82, |
412 | 0 | 0xda, |
413 | 0 | 0x4b, |
414 | 0 | 0x2c |
415 | 0 | }; |
416 | |
|
417 | 0 | delegUsageOid.data = kDelegationUsageOid; |
418 | 0 | delegUsageOid.len = sizeof kDelegationUsageOid; |
419 | | |
420 | | /* The certificate must have the delegationUsage extension that authorizes |
421 | | * it to negotiate delegated credentials. |
422 | | */ |
423 | 0 | found = PR_FALSE; |
424 | 0 | for (i = 0; cert->extensions[i] != NULL; i++) { |
425 | 0 | ext = cert->extensions[i]; |
426 | 0 | if (SECITEM_CompareItem(&ext->id, &delegUsageOid) == SECEqual) { |
427 | 0 | found = PR_TRUE; |
428 | 0 | break; |
429 | 0 | } |
430 | 0 | } |
431 | | |
432 | | /* The certificate must also have the digitalSignature keyUsage set. */ |
433 | 0 | if (!found || |
434 | 0 | !cert->keyUsagePresent || |
435 | 0 | !(cert->keyUsage & KU_DIGITAL_SIGNATURE)) { |
436 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_INVALID_KEY_USAGE, illegal_parameter); |
437 | 0 | return SECFailure; |
438 | 0 | } |
439 | | |
440 | 0 | return SECSuccess; |
441 | 0 | } |
442 | | |
443 | | static SECStatus |
444 | | tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc) |
445 | 0 | { |
446 | 0 | SECStatus rv; |
447 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
448 | | /* 7 days in microseconds */ |
449 | 0 | static const PRTime kMaxDcValidity = ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC); |
450 | 0 | PRTime start, now, end; /* microseconds */ |
451 | |
|
452 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
453 | 0 | if (rv != SECSuccess) { |
454 | 0 | FATAL_ERROR(ss, PORT_GetError(), internal_error); |
455 | 0 | return SECFailure; |
456 | 0 | } |
457 | | |
458 | 0 | end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC); |
459 | 0 | now = ssl_Time(ss); |
460 | 0 | if (now > end || end < 0) { |
461 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter); |
462 | 0 | return SECFailure; |
463 | 0 | } |
464 | | |
465 | | /* Not more than 7 days remaining in the validity period. */ |
466 | 0 | if (end - now > kMaxDcValidity) { |
467 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, illegal_parameter); |
468 | 0 | return SECFailure; |
469 | 0 | } |
470 | | |
471 | 0 | return SECSuccess; |
472 | 0 | } |
473 | | |
474 | | /* Returns SECSucces if |dc| is a DC for the current handshake; otherwise it |
475 | | * returns SECFailure. A valid DC meets three requirements: (1) the signature |
476 | | * was produced by the peer's end-entity certificate, (2) the end-entity |
477 | | * certificate must have the correct key usage, and (3) the DC must not be |
478 | | * expired and its remaining TTL must be <= the maximum validity period (fixed |
479 | | * as 7 days). |
480 | | * |
481 | | * This function calls FATAL_ERROR() when an error occurs. |
482 | | */ |
483 | | SECStatus |
484 | | tls13_VerifyDelegatedCredential(sslSocket *ss, |
485 | | sslDelegatedCredential *dc) |
486 | 0 | { |
487 | 0 | SECStatus rv; |
488 | 0 | PRTime start; |
489 | 0 | PRExplodedTime end; |
490 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
491 | 0 | char endStr[256]; |
492 | |
|
493 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
494 | 0 | if (rv != SECSuccess) { |
495 | 0 | FATAL_ERROR(ss, PORT_GetError(), internal_error); |
496 | 0 | return SECFailure; |
497 | 0 | } |
498 | | |
499 | 0 | PR_ExplodeTime(start + (dc->validTime * PR_USEC_PER_SEC), |
500 | 0 | PR_GMTParameters, &end); |
501 | 0 | if (PR_FormatTime(endStr, sizeof(endStr), "%a %b %d %H:%M:%S %Y", &end)) { |
502 | 0 | SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential (expires %s)", |
503 | 0 | SSL_GETPID(), ss->fd, endStr)); |
504 | 0 | } else { |
505 | 0 | SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential", |
506 | 0 | SSL_GETPID(), ss->fd)); |
507 | 0 | } |
508 | |
|
509 | 0 | rv = SECSuccess; |
510 | 0 | rv |= tls13_VerifyCredentialSignature(ss, dc); |
511 | 0 | rv |= tls13_CheckCertDelegationUsage(ss); |
512 | 0 | rv |= tls13_CheckCredentialExpiration(ss, dc); |
513 | 0 | return rv; |
514 | 0 | } |
515 | | |
516 | | static CERTSubjectPublicKeyInfo * |
517 | | tls13_MakePssSpki(const SECKEYPublicKey *pub, SECOidTag hashOid) |
518 | 0 | { |
519 | 0 | SECStatus rv; |
520 | 0 | PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
521 | 0 | if (!arena) { |
522 | 0 | goto loser; /* Code already set. */ |
523 | 0 | } |
524 | 0 | CERTSubjectPublicKeyInfo *spki = PORT_ArenaZNew(arena, CERTSubjectPublicKeyInfo); |
525 | 0 | if (!spki) { |
526 | 0 | goto loser; /* Code already set. */ |
527 | 0 | } |
528 | 0 | spki->arena = arena; |
529 | |
|
530 | 0 | SECKEYRSAPSSParams params = { 0 }; |
531 | 0 | params.hashAlg = PORT_ArenaZNew(arena, SECAlgorithmID); |
532 | 0 | rv = SECOID_SetAlgorithmID(arena, params.hashAlg, hashOid, NULL); |
533 | 0 | if (rv != SECSuccess) { |
534 | 0 | goto loser; /* Code already set. */ |
535 | 0 | } |
536 | | |
537 | | /* Set the mask hash algorithm too, which is an argument to |
538 | | * a SEC_OID_PKCS1_MGF1 value. */ |
539 | 0 | SECAlgorithmID maskHashAlg; |
540 | 0 | memset(&maskHashAlg, 0, sizeof(maskHashAlg)); |
541 | 0 | rv = SECOID_SetAlgorithmID(arena, &maskHashAlg, hashOid, NULL); |
542 | 0 | if (rv != SECSuccess) { |
543 | 0 | goto loser; /* Code already set. */ |
544 | 0 | } |
545 | 0 | SECItem *maskHashAlgItem = |
546 | 0 | SEC_ASN1EncodeItem(arena, NULL, &maskHashAlg, |
547 | 0 | SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); |
548 | 0 | if (!maskHashAlgItem) { |
549 | | /* Probably OOM, but not certain. */ |
550 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
551 | 0 | goto loser; |
552 | 0 | } |
553 | | |
554 | 0 | params.maskAlg = PORT_ArenaZNew(arena, SECAlgorithmID); |
555 | 0 | rv = SECOID_SetAlgorithmID(arena, params.maskAlg, SEC_OID_PKCS1_MGF1, |
556 | 0 | maskHashAlgItem); |
557 | 0 | if (rv != SECSuccess) { |
558 | 0 | goto loser; /* Code already set. */ |
559 | 0 | } |
560 | | |
561 | | /* Always include saltLength: all hashes are larger than 20. */ |
562 | 0 | unsigned int saltLength = HASH_ResultLenByOidTag(hashOid); |
563 | 0 | PORT_Assert(saltLength > 20); |
564 | 0 | if (!SEC_ASN1EncodeInteger(arena, ¶ms.saltLength, saltLength)) { |
565 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
566 | 0 | goto loser; |
567 | 0 | } |
568 | | /* Omit the trailerField always. */ |
569 | | |
570 | 0 | SECItem *algorithmItem = |
571 | 0 | SEC_ASN1EncodeItem(arena, NULL, ¶ms, |
572 | 0 | SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); |
573 | 0 | if (!algorithmItem) { |
574 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
575 | 0 | goto loser; /* Code already set. */ |
576 | 0 | } |
577 | 0 | rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, |
578 | 0 | SEC_OID_PKCS1_RSA_PSS_SIGNATURE, algorithmItem); |
579 | 0 | if (rv != SECSuccess) { |
580 | 0 | goto loser; /* Code already set. */ |
581 | 0 | } |
582 | | |
583 | 0 | SECItem *pubItem = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, pub, |
584 | 0 | SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate)); |
585 | 0 | if (!pubItem) { |
586 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
587 | 0 | goto loser; |
588 | 0 | } |
589 | 0 | spki->subjectPublicKey.len *= 8; /* Key length is in bits. */ |
590 | 0 | return spki; |
591 | | |
592 | 0 | loser: |
593 | 0 | PORT_FreeArena(arena, PR_FALSE); |
594 | 0 | return NULL; |
595 | 0 | } |
596 | | |
597 | | static CERTSubjectPublicKeyInfo * |
598 | | tls13_MakeDcSpki(const SECKEYPublicKey *dcPub, SSLSignatureScheme dcCertVerifyAlg) |
599 | 0 | { |
600 | 0 | switch (SECKEY_GetPublicKeyType(dcPub)) { |
601 | 0 | case rsaKey: { |
602 | 0 | SECOidTag hashOid; |
603 | 0 | switch (dcCertVerifyAlg) { |
604 | | /* Note: RSAE schemes are NOT permitted within DC SPKIs. However, |
605 | | * support for their issuance remains so as to enable negative |
606 | | * testing of client behavior. */ |
607 | 0 | case ssl_sig_rsa_pss_rsae_sha256: |
608 | 0 | case ssl_sig_rsa_pss_rsae_sha384: |
609 | 0 | case ssl_sig_rsa_pss_rsae_sha512: |
610 | 0 | return SECKEY_CreateSubjectPublicKeyInfo(dcPub); |
611 | 0 | case ssl_sig_rsa_pss_pss_sha256: |
612 | 0 | hashOid = SEC_OID_SHA256; |
613 | 0 | break; |
614 | 0 | case ssl_sig_rsa_pss_pss_sha384: |
615 | 0 | hashOid = SEC_OID_SHA384; |
616 | 0 | break; |
617 | 0 | case ssl_sig_rsa_pss_pss_sha512: |
618 | 0 | hashOid = SEC_OID_SHA512; |
619 | 0 | break; |
620 | | |
621 | 0 | default: |
622 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
623 | 0 | return NULL; |
624 | 0 | } |
625 | 0 | return tls13_MakePssSpki(dcPub, hashOid); |
626 | 0 | } |
627 | | |
628 | 0 | case ecKey: { |
629 | 0 | const sslNamedGroupDef *group = ssl_ECPubKey2NamedGroup(dcPub); |
630 | 0 | if (!group) { |
631 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
632 | 0 | return NULL; |
633 | 0 | } |
634 | 0 | SSLSignatureScheme keyScheme; |
635 | 0 | switch (group->name) { |
636 | 0 | case ssl_grp_ec_secp256r1: |
637 | 0 | keyScheme = ssl_sig_ecdsa_secp256r1_sha256; |
638 | 0 | break; |
639 | 0 | case ssl_grp_ec_secp384r1: |
640 | 0 | keyScheme = ssl_sig_ecdsa_secp384r1_sha384; |
641 | 0 | break; |
642 | 0 | case ssl_grp_ec_secp521r1: |
643 | 0 | keyScheme = ssl_sig_ecdsa_secp521r1_sha512; |
644 | 0 | break; |
645 | 0 | default: |
646 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
647 | 0 | return NULL; |
648 | 0 | } |
649 | 0 | if (keyScheme != dcCertVerifyAlg) { |
650 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
651 | 0 | return NULL; |
652 | 0 | } |
653 | 0 | return SECKEY_CreateSubjectPublicKeyInfo(dcPub); |
654 | 0 | } |
655 | | |
656 | 0 | default: |
657 | 0 | break; |
658 | 0 | } |
659 | | |
660 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
661 | 0 | return NULL; |
662 | 0 | } |
663 | | |
664 | | /* Returns a serialized DC with the given parameters. |
665 | | * |
666 | | * Note that this function is meant primarily for testing. In particular, it |
667 | | * DOES NOT verify any of the following: |
668 | | * - |certPriv| is the private key corresponding to |cert|; |
669 | | * - that |checkCertKeyUsage(cert) == SECSuccess|; |
670 | | * - |dcValidFor| is less than 7 days (the maximum permitted by the spec); or |
671 | | * - validTime doesn't overflow a PRUint32. |
672 | | * |
673 | | * These conditions are things we want to test for, which is why we allow them |
674 | | * here. A real API for creating DCs would want to explicitly check ALL of these |
675 | | * conditions are met. |
676 | | */ |
677 | | SECStatus |
678 | | SSLExp_DelegateCredential(const CERTCertificate *cert, |
679 | | const SECKEYPrivateKey *certPriv, |
680 | | const SECKEYPublicKey *dcPub, |
681 | | SSLSignatureScheme dcCertVerifyAlg, |
682 | | PRUint32 dcValidFor, |
683 | | PRTime now, |
684 | | SECItem *out) |
685 | 0 | { |
686 | 0 | SECStatus rv; |
687 | 0 | CERTSubjectPublicKeyInfo *spki = NULL; |
688 | 0 | SECKEYPrivateKey *tmpPriv = NULL; |
689 | 0 | void *pwArg = certPriv->wincx; |
690 | 0 | sslDelegatedCredential *dc = NULL; |
691 | 0 | sslBuffer dcBuf = SSL_BUFFER_EMPTY; |
692 | |
|
693 | 0 | if (!cert || !certPriv || !dcPub || !out) { |
694 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
695 | 0 | return SECFailure; |
696 | 0 | } |
697 | | |
698 | 0 | dc = PORT_ZNew(sslDelegatedCredential); |
699 | 0 | if (!dc) { |
700 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
701 | 0 | goto loser; |
702 | 0 | } |
703 | | |
704 | | /* Serialize the DC parameters. */ |
705 | 0 | PRTime start; |
706 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
707 | 0 | if (rv != SECSuccess) { |
708 | 0 | goto loser; |
709 | 0 | } |
710 | 0 | dc->validTime = ((now - start) / PR_USEC_PER_SEC) + dcValidFor; |
711 | | |
712 | | /* Building the SPKI also validates |dcCertVerifyAlg|. */ |
713 | 0 | spki = tls13_MakeDcSpki(dcPub, dcCertVerifyAlg); |
714 | 0 | if (!spki) { |
715 | 0 | goto loser; |
716 | 0 | } |
717 | 0 | dc->expectedCertVerifyAlg = dcCertVerifyAlg; |
718 | |
|
719 | 0 | SECItem *spkiDer = |
720 | 0 | SEC_ASN1EncodeItem(NULL /*arena*/, &dc->derSpki, spki, |
721 | 0 | SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate)); |
722 | 0 | if (!spkiDer) { |
723 | 0 | goto loser; |
724 | 0 | } |
725 | | |
726 | 0 | rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, |
727 | 0 | PR_TRUE /* isTls13 */, &dc->alg); |
728 | 0 | if (rv != SECSuccess) { |
729 | 0 | goto loser; |
730 | 0 | } |
731 | | |
732 | 0 | if (dc->alg == ssl_sig_none) { |
733 | 0 | SECOidTag spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); |
734 | | /* If the Cert SPKI contained an AlgorithmIdentifier of "rsaEncryption", set a |
735 | | * default rsa_pss_rsae_sha256 scheme. NOTE: RSAE SPKIs are not permitted within |
736 | | * "real" Delegated Credentials. However, since this function is primarily used for |
737 | | * testing, we retain this support in order to verify that these DCs are rejected |
738 | | * by tls13_VerifyDelegatedCredential. */ |
739 | 0 | if (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION) { |
740 | 0 | SSLSignatureScheme scheme = ssl_sig_rsa_pss_rsae_sha256; |
741 | 0 | if (ssl_SignatureSchemeValid(scheme, spkiOid, PR_TRUE /* isTls13 */)) { |
742 | 0 | dc->alg = scheme; |
743 | 0 | } |
744 | 0 | } |
745 | 0 | } |
746 | 0 | PORT_Assert(dc->alg != ssl_sig_none); |
747 | |
|
748 | 0 | rv = tls13_AppendCredentialParams(&dcBuf, dc); |
749 | 0 | if (rv != SECSuccess) { |
750 | 0 | goto loser; |
751 | 0 | } |
752 | | |
753 | | /* Sign the hash with the delegation key. |
754 | | * |
755 | | * The PK11 API discards const qualifiers, so we have to make a copy of |
756 | | * |certPriv| and pass the copy to |
757 | | * |tls13_HashCredentialAndSignOrVerifyMessage|. |
758 | | */ |
759 | 0 | tmpPriv = SECKEY_CopyPrivateKey(certPriv); |
760 | 0 | rv = tls13_HashCredentialAndSignOrVerifyMessage(tmpPriv, NULL, dc->alg, |
761 | 0 | sig_sign, cert, &dcBuf, |
762 | 0 | &dc->signature, pwArg); |
763 | 0 | if (rv != SECSuccess) { |
764 | 0 | goto loser; |
765 | 0 | } |
766 | | |
767 | | /* Serialize the DC signature. */ |
768 | 0 | rv = tls13_AppendCredentialSignature(&dcBuf, dc); |
769 | 0 | if (rv != SECSuccess) { |
770 | 0 | goto loser; |
771 | 0 | } |
772 | | |
773 | | /* Copy the serialized DC to |out|. */ |
774 | 0 | rv = SECITEM_MakeItem(NULL, out, dcBuf.buf, dcBuf.len); |
775 | 0 | if (rv != SECSuccess) { |
776 | 0 | goto loser; |
777 | 0 | } |
778 | | |
779 | 0 | PRINT_BUF(20, (NULL, "delegated credential", dcBuf.buf, dcBuf.len)); |
780 | |
|
781 | 0 | SECKEY_DestroySubjectPublicKeyInfo(spki); |
782 | 0 | SECKEY_DestroyPrivateKey(tmpPriv); |
783 | 0 | tls13_DestroyDelegatedCredential(dc); |
784 | 0 | sslBuffer_Clear(&dcBuf); |
785 | 0 | return SECSuccess; |
786 | | |
787 | 0 | loser: |
788 | 0 | SECKEY_DestroySubjectPublicKeyInfo(spki); |
789 | 0 | SECKEY_DestroyPrivateKey(tmpPriv); |
790 | 0 | tls13_DestroyDelegatedCredential(dc); |
791 | 0 | sslBuffer_Clear(&dcBuf); |
792 | 0 | return SECFailure; |
793 | 0 | } |