/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 | 349k | { |
109 | 349k | if (!dc) { |
110 | 349k | return; |
111 | 349k | } |
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.74k | { |
166 | 2.74k | if (!ss->sec.isServer || |
167 | 2.74k | !ss->xtnData.sendingDelegCredToPeer || |
168 | 2.74k | !ss->xtnData.peerRequestedDelegCred) { |
169 | 2.74k | return PR_FALSE; |
170 | 2.74k | } |
171 | | |
172 | 0 | return PR_TRUE; |
173 | 2.74k | } |
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.90k | { |
188 | 2.90k | SECStatus rv; |
189 | 2.90k | PRBool doesRsaPss; |
190 | 2.90k | SECKEYPrivateKey *priv; |
191 | 2.90k | 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.90k | PORT_Assert(ss->sec.isServer); |
199 | 2.90k | PORT_Assert(ss->sec.serverCert); |
200 | 2.90k | PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); |
201 | 2.90k | 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.90k | if (!ss->xtnData.peerRequestedDelegCred || |
207 | 9 | !ss->xtnData.delegCredSigSchemes || |
208 | 9 | !ss->sec.serverCert->delegCred.len || |
209 | 2.90k | !ss->sec.serverCert->delegCredKeyPair) { |
210 | 2.90k | return SECSuccess; |
211 | 2.90k | } |
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 | if (cert->extensions) { |
425 | 0 | for (i = 0; cert->extensions[i] != NULL; i++) { |
426 | 0 | ext = cert->extensions[i]; |
427 | 0 | if (SECITEM_CompareItem(&ext->id, &delegUsageOid) == SECEqual) { |
428 | 0 | found = PR_TRUE; |
429 | 0 | break; |
430 | 0 | } |
431 | 0 | } |
432 | 0 | } |
433 | | |
434 | | /* The certificate must also have the digitalSignature keyUsage set. */ |
435 | 0 | if (!found || |
436 | 0 | !cert->keyUsagePresent || |
437 | 0 | !(cert->keyUsage & KU_DIGITAL_SIGNATURE)) { |
438 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_INVALID_KEY_USAGE, illegal_parameter); |
439 | 0 | return SECFailure; |
440 | 0 | } |
441 | | |
442 | 0 | return SECSuccess; |
443 | 0 | } |
444 | | |
445 | | static SECStatus |
446 | | tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc) |
447 | 0 | { |
448 | 0 | SECStatus rv; |
449 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
450 | | /* 7 days in microseconds */ |
451 | 0 | static const PRTime kMaxDcValidity = ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC); |
452 | 0 | PRTime start, now, end; /* microseconds */ |
453 | |
|
454 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
455 | 0 | if (rv != SECSuccess) { |
456 | 0 | FATAL_ERROR(ss, PORT_GetError(), internal_error); |
457 | 0 | return SECFailure; |
458 | 0 | } |
459 | | |
460 | 0 | end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC); |
461 | 0 | now = ssl_Time(ss); |
462 | 0 | if (now > end || end < 0) { |
463 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter); |
464 | 0 | return SECFailure; |
465 | 0 | } |
466 | | |
467 | | /* Not more than 7 days remaining in the validity period. */ |
468 | 0 | if (end - now > kMaxDcValidity) { |
469 | 0 | FATAL_ERROR(ss, SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, illegal_parameter); |
470 | 0 | return SECFailure; |
471 | 0 | } |
472 | | |
473 | 0 | return SECSuccess; |
474 | 0 | } |
475 | | |
476 | | /* Returns SECSucces if |dc| is a DC for the current handshake; otherwise it |
477 | | * returns SECFailure. A valid DC meets three requirements: (1) the signature |
478 | | * was produced by the peer's end-entity certificate, (2) the end-entity |
479 | | * certificate must have the correct key usage, and (3) the DC must not be |
480 | | * expired and its remaining TTL must be <= the maximum validity period (fixed |
481 | | * as 7 days). |
482 | | * |
483 | | * This function calls FATAL_ERROR() when an error occurs. |
484 | | */ |
485 | | SECStatus |
486 | | tls13_VerifyDelegatedCredential(sslSocket *ss, |
487 | | sslDelegatedCredential *dc) |
488 | 0 | { |
489 | 0 | SECStatus rv; |
490 | 0 | PRTime start; |
491 | 0 | PRExplodedTime end; |
492 | 0 | CERTCertificate *cert = ss->sec.peerCert; |
493 | 0 | char endStr[256]; |
494 | |
|
495 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
496 | 0 | if (rv != SECSuccess) { |
497 | 0 | FATAL_ERROR(ss, PORT_GetError(), internal_error); |
498 | 0 | return SECFailure; |
499 | 0 | } |
500 | | |
501 | 0 | PR_ExplodeTime(start + (dc->validTime * PR_USEC_PER_SEC), |
502 | 0 | PR_GMTParameters, &end); |
503 | 0 | if (PR_FormatTime(endStr, sizeof(endStr), "%a %b %d %H:%M:%S %Y", &end)) { |
504 | 0 | SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential (expires %s)", |
505 | 0 | SSL_GETPID(), ss->fd, endStr)); |
506 | 0 | } else { |
507 | 0 | SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential", |
508 | 0 | SSL_GETPID(), ss->fd)); |
509 | 0 | } |
510 | |
|
511 | 0 | rv = SECSuccess; |
512 | 0 | rv |= tls13_VerifyCredentialSignature(ss, dc); |
513 | 0 | rv |= tls13_CheckCertDelegationUsage(ss); |
514 | 0 | rv |= tls13_CheckCredentialExpiration(ss, dc); |
515 | 0 | return rv; |
516 | 0 | } |
517 | | |
518 | | static CERTSubjectPublicKeyInfo * |
519 | | tls13_MakePssSpki(const SECKEYPublicKey *pub, SECOidTag hashOid) |
520 | 0 | { |
521 | 0 | SECStatus rv; |
522 | 0 | PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
523 | 0 | if (!arena) { |
524 | 0 | goto loser; /* Code already set. */ |
525 | 0 | } |
526 | 0 | CERTSubjectPublicKeyInfo *spki = PORT_ArenaZNew(arena, CERTSubjectPublicKeyInfo); |
527 | 0 | if (!spki) { |
528 | 0 | goto loser; /* Code already set. */ |
529 | 0 | } |
530 | 0 | spki->arena = arena; |
531 | |
|
532 | 0 | SECKEYRSAPSSParams params = { 0 }; |
533 | 0 | params.hashAlg = PORT_ArenaZNew(arena, SECAlgorithmID); |
534 | 0 | rv = SECOID_SetAlgorithmID(arena, params.hashAlg, hashOid, NULL); |
535 | 0 | if (rv != SECSuccess) { |
536 | 0 | goto loser; /* Code already set. */ |
537 | 0 | } |
538 | | |
539 | | /* Set the mask hash algorithm too, which is an argument to |
540 | | * a SEC_OID_PKCS1_MGF1 value. */ |
541 | 0 | SECAlgorithmID maskHashAlg; |
542 | 0 | memset(&maskHashAlg, 0, sizeof(maskHashAlg)); |
543 | 0 | rv = SECOID_SetAlgorithmID(arena, &maskHashAlg, hashOid, NULL); |
544 | 0 | if (rv != SECSuccess) { |
545 | 0 | goto loser; /* Code already set. */ |
546 | 0 | } |
547 | 0 | SECItem *maskHashAlgItem = |
548 | 0 | SEC_ASN1EncodeItem(arena, NULL, &maskHashAlg, |
549 | 0 | SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); |
550 | 0 | if (!maskHashAlgItem) { |
551 | | /* Probably OOM, but not certain. */ |
552 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
553 | 0 | goto loser; |
554 | 0 | } |
555 | | |
556 | 0 | params.maskAlg = PORT_ArenaZNew(arena, SECAlgorithmID); |
557 | 0 | rv = SECOID_SetAlgorithmID(arena, params.maskAlg, SEC_OID_PKCS1_MGF1, |
558 | 0 | maskHashAlgItem); |
559 | 0 | if (rv != SECSuccess) { |
560 | 0 | goto loser; /* Code already set. */ |
561 | 0 | } |
562 | | |
563 | | /* Always include saltLength: all hashes are larger than 20. */ |
564 | 0 | unsigned int saltLength = HASH_ResultLenByOidTag(hashOid); |
565 | 0 | PORT_Assert(saltLength > 20); |
566 | 0 | if (!SEC_ASN1EncodeInteger(arena, ¶ms.saltLength, saltLength)) { |
567 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
568 | 0 | goto loser; |
569 | 0 | } |
570 | | /* Omit the trailerField always. */ |
571 | | |
572 | 0 | SECItem *algorithmItem = |
573 | 0 | SEC_ASN1EncodeItem(arena, NULL, ¶ms, |
574 | 0 | SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); |
575 | 0 | if (!algorithmItem) { |
576 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
577 | 0 | goto loser; /* Code already set. */ |
578 | 0 | } |
579 | 0 | rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, |
580 | 0 | SEC_OID_PKCS1_RSA_PSS_SIGNATURE, algorithmItem); |
581 | 0 | if (rv != SECSuccess) { |
582 | 0 | goto loser; /* Code already set. */ |
583 | 0 | } |
584 | | |
585 | 0 | SECItem *pubItem = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, pub, |
586 | 0 | SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate)); |
587 | 0 | if (!pubItem) { |
588 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
589 | 0 | goto loser; |
590 | 0 | } |
591 | 0 | spki->subjectPublicKey.len *= 8; /* Key length is in bits. */ |
592 | 0 | return spki; |
593 | | |
594 | 0 | loser: |
595 | 0 | PORT_FreeArena(arena, PR_FALSE); |
596 | 0 | return NULL; |
597 | 0 | } |
598 | | |
599 | | static CERTSubjectPublicKeyInfo * |
600 | | tls13_MakeDcSpki(const SECKEYPublicKey *dcPub, SSLSignatureScheme dcCertVerifyAlg) |
601 | 0 | { |
602 | 0 | switch (SECKEY_GetPublicKeyType(dcPub)) { |
603 | 0 | case rsaKey: { |
604 | 0 | SECOidTag hashOid; |
605 | 0 | switch (dcCertVerifyAlg) { |
606 | | /* Note: RSAE schemes are NOT permitted within DC SPKIs. However, |
607 | | * support for their issuance remains so as to enable negative |
608 | | * testing of client behavior. */ |
609 | 0 | case ssl_sig_rsa_pss_rsae_sha256: |
610 | 0 | case ssl_sig_rsa_pss_rsae_sha384: |
611 | 0 | case ssl_sig_rsa_pss_rsae_sha512: |
612 | 0 | return SECKEY_CreateSubjectPublicKeyInfo(dcPub); |
613 | 0 | case ssl_sig_rsa_pss_pss_sha256: |
614 | 0 | hashOid = SEC_OID_SHA256; |
615 | 0 | break; |
616 | 0 | case ssl_sig_rsa_pss_pss_sha384: |
617 | 0 | hashOid = SEC_OID_SHA384; |
618 | 0 | break; |
619 | 0 | case ssl_sig_rsa_pss_pss_sha512: |
620 | 0 | hashOid = SEC_OID_SHA512; |
621 | 0 | break; |
622 | | |
623 | 0 | default: |
624 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
625 | 0 | return NULL; |
626 | 0 | } |
627 | 0 | return tls13_MakePssSpki(dcPub, hashOid); |
628 | 0 | } |
629 | | |
630 | 0 | case ecKey: { |
631 | 0 | const sslNamedGroupDef *group = ssl_ECPubKey2NamedGroup(dcPub); |
632 | 0 | if (!group) { |
633 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
634 | 0 | return NULL; |
635 | 0 | } |
636 | 0 | SSLSignatureScheme keyScheme; |
637 | 0 | switch (group->name) { |
638 | 0 | case ssl_grp_ec_secp256r1: |
639 | 0 | keyScheme = ssl_sig_ecdsa_secp256r1_sha256; |
640 | 0 | break; |
641 | 0 | case ssl_grp_ec_secp384r1: |
642 | 0 | keyScheme = ssl_sig_ecdsa_secp384r1_sha384; |
643 | 0 | break; |
644 | 0 | case ssl_grp_ec_secp521r1: |
645 | 0 | keyScheme = ssl_sig_ecdsa_secp521r1_sha512; |
646 | 0 | break; |
647 | 0 | default: |
648 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
649 | 0 | return NULL; |
650 | 0 | } |
651 | 0 | if (keyScheme != dcCertVerifyAlg) { |
652 | 0 | PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
653 | 0 | return NULL; |
654 | 0 | } |
655 | 0 | return SECKEY_CreateSubjectPublicKeyInfo(dcPub); |
656 | 0 | } |
657 | | |
658 | 0 | default: |
659 | 0 | break; |
660 | 0 | } |
661 | | |
662 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
663 | 0 | return NULL; |
664 | 0 | } |
665 | | |
666 | | /* Returns a serialized DC with the given parameters. |
667 | | * |
668 | | * Note that this function is meant primarily for testing. In particular, it |
669 | | * DOES NOT verify any of the following: |
670 | | * - |certPriv| is the private key corresponding to |cert|; |
671 | | * - that |checkCertKeyUsage(cert) == SECSuccess|; |
672 | | * - |dcValidFor| is less than 7 days (the maximum permitted by the spec); or |
673 | | * - validTime doesn't overflow a PRUint32. |
674 | | * |
675 | | * These conditions are things we want to test for, which is why we allow them |
676 | | * here. A real API for creating DCs would want to explicitly check ALL of these |
677 | | * conditions are met. |
678 | | */ |
679 | | SECStatus |
680 | | SSLExp_DelegateCredential(const CERTCertificate *cert, |
681 | | const SECKEYPrivateKey *certPriv, |
682 | | const SECKEYPublicKey *dcPub, |
683 | | SSLSignatureScheme dcCertVerifyAlg, |
684 | | PRUint32 dcValidFor, |
685 | | PRTime now, |
686 | | SECItem *out) |
687 | 0 | { |
688 | 0 | SECStatus rv; |
689 | 0 | CERTSubjectPublicKeyInfo *spki = NULL; |
690 | 0 | SECKEYPrivateKey *tmpPriv = NULL; |
691 | 0 | void *pwArg = certPriv->wincx; |
692 | 0 | sslDelegatedCredential *dc = NULL; |
693 | 0 | sslBuffer dcBuf = SSL_BUFFER_EMPTY; |
694 | |
|
695 | 0 | if (!cert || !certPriv || !dcPub || !out) { |
696 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
697 | 0 | return SECFailure; |
698 | 0 | } |
699 | | |
700 | 0 | dc = PORT_ZNew(sslDelegatedCredential); |
701 | 0 | if (!dc) { |
702 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
703 | 0 | goto loser; |
704 | 0 | } |
705 | | |
706 | | /* Serialize the DC parameters. */ |
707 | 0 | PRTime start; |
708 | 0 | rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); |
709 | 0 | if (rv != SECSuccess) { |
710 | 0 | goto loser; |
711 | 0 | } |
712 | 0 | dc->validTime = ((now - start) / PR_USEC_PER_SEC) + dcValidFor; |
713 | | |
714 | | /* Building the SPKI also validates |dcCertVerifyAlg|. */ |
715 | 0 | spki = tls13_MakeDcSpki(dcPub, dcCertVerifyAlg); |
716 | 0 | if (!spki) { |
717 | 0 | goto loser; |
718 | 0 | } |
719 | 0 | dc->expectedCertVerifyAlg = dcCertVerifyAlg; |
720 | |
|
721 | 0 | SECItem *spkiDer = |
722 | 0 | SEC_ASN1EncodeItem(NULL /*arena*/, &dc->derSpki, spki, |
723 | 0 | SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate)); |
724 | 0 | if (!spkiDer) { |
725 | 0 | goto loser; |
726 | 0 | } |
727 | | |
728 | 0 | rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, |
729 | 0 | PR_TRUE /* isTls13 */, &dc->alg); |
730 | 0 | if (rv != SECSuccess) { |
731 | 0 | goto loser; |
732 | 0 | } |
733 | | |
734 | 0 | if (dc->alg == ssl_sig_none) { |
735 | 0 | SECOidTag spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); |
736 | | /* If the Cert SPKI contained an AlgorithmIdentifier of "rsaEncryption", set a |
737 | | * default rsa_pss_rsae_sha256 scheme. NOTE: RSAE SPKIs are not permitted within |
738 | | * "real" Delegated Credentials. However, since this function is primarily used for |
739 | | * testing, we retain this support in order to verify that these DCs are rejected |
740 | | * by tls13_VerifyDelegatedCredential. */ |
741 | 0 | if (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION) { |
742 | 0 | SSLSignatureScheme scheme = ssl_sig_rsa_pss_rsae_sha256; |
743 | 0 | if (ssl_SignatureSchemeValid(scheme, spkiOid, PR_TRUE /* isTls13 */)) { |
744 | 0 | dc->alg = scheme; |
745 | 0 | } |
746 | 0 | } |
747 | 0 | } |
748 | 0 | PORT_Assert(dc->alg != ssl_sig_none); |
749 | |
|
750 | 0 | rv = tls13_AppendCredentialParams(&dcBuf, dc); |
751 | 0 | if (rv != SECSuccess) { |
752 | 0 | goto loser; |
753 | 0 | } |
754 | | |
755 | | /* Sign the hash with the delegation key. |
756 | | * |
757 | | * The PK11 API discards const qualifiers, so we have to make a copy of |
758 | | * |certPriv| and pass the copy to |
759 | | * |tls13_HashCredentialAndSignOrVerifyMessage|. |
760 | | */ |
761 | 0 | tmpPriv = SECKEY_CopyPrivateKey(certPriv); |
762 | 0 | rv = tls13_HashCredentialAndSignOrVerifyMessage(tmpPriv, NULL, dc->alg, |
763 | 0 | sig_sign, cert, &dcBuf, |
764 | 0 | &dc->signature, pwArg); |
765 | 0 | if (rv != SECSuccess) { |
766 | 0 | goto loser; |
767 | 0 | } |
768 | | |
769 | | /* Serialize the DC signature. */ |
770 | 0 | rv = tls13_AppendCredentialSignature(&dcBuf, dc); |
771 | 0 | if (rv != SECSuccess) { |
772 | 0 | goto loser; |
773 | 0 | } |
774 | | |
775 | | /* Copy the serialized DC to |out|. */ |
776 | 0 | rv = SECITEM_MakeItem(NULL, out, dcBuf.buf, dcBuf.len); |
777 | 0 | if (rv != SECSuccess) { |
778 | 0 | goto loser; |
779 | 0 | } |
780 | | |
781 | 0 | PRINT_BUF(20, (NULL, "delegated credential", dcBuf.buf, dcBuf.len)); |
782 | |
|
783 | 0 | SECKEY_DestroySubjectPublicKeyInfo(spki); |
784 | 0 | SECKEY_DestroyPrivateKey(tmpPriv); |
785 | 0 | tls13_DestroyDelegatedCredential(dc); |
786 | 0 | sslBuffer_Clear(&dcBuf); |
787 | 0 | return SECSuccess; |
788 | | |
789 | 0 | loser: |
790 | 0 | SECKEY_DestroySubjectPublicKeyInfo(spki); |
791 | 0 | SECKEY_DestroyPrivateKey(tmpPriv); |
792 | 0 | tls13_DestroyDelegatedCredential(dc); |
793 | 0 | sslBuffer_Clear(&dcBuf); |
794 | 0 | return SECFailure; |
795 | 0 | } |