/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Parses the delegated credential (DC) from the raw extension |b| of length * |length|. Memory for the DC is allocated and set to |*dcp|. * * It's the caller's responsibility to invoke |tls13_DestroyDelegatedCredential| * when this data is no longer needed.
*/
SECStatus
tls13_ReadDelegatedCredential(PRUint8 *b, PRUint32 length,
sslDelegatedCredential **dcp)
{
sslDelegatedCredential *dc = NULL;
SECStatus rv;
PRUint64 n;
sslReadBuffer tmp;
sslReader rdr = SSL_READER(b, length);
PORT_Assert(!*dcp);
dc = PORT_ZNew(sslDelegatedCredential); if (!dc) {
PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser;
}
/* Read the valid_time field of DelegatedCredential.cred. */
rv = sslRead_ReadNumber(&rdr, 4, &n); if (rv != SECSuccess) { goto loser;
}
dc->validTime = n;
/* Read the expected_cert_verify_algorithm field of
* DelegatedCredential.cred. */
rv = sslRead_ReadNumber(&rdr, 2, &n); if (rv != SECSuccess) { goto loser;
}
dc->expectedCertVerifyAlg = n;
/* Read the ASN1_subjectPublicKeyInfo field of DelegatedCredential.cred. */
rv = sslRead_ReadVariable(&rdr, 3, &tmp); if (rv != SECSuccess) { goto loser;
}
rv = SECITEM_MakeItem(NULL, &dc->derSpki, tmp.buf, tmp.len); if (rv != SECSuccess) { goto loser;
}
/* Parse the DER-encoded SubjectPublicKeyInfo. */
dc->spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&dc->derSpki); if (!dc->spki) { goto loser;
}
/* Read the algorithm field of the DelegatedCredential. */
rv = sslRead_ReadNumber(&rdr, 2, &n); if (rv != SECSuccess) { goto loser;
}
dc->alg = n;
/* Read the signature field of the DelegatedCredential. */
rv = sslRead_ReadVariable(&rdr, 2, &tmp); if (rv != SECSuccess) { goto loser;
}
rv = SECITEM_MakeItem(NULL, &dc->signature, tmp.buf, tmp.len); if (rv != SECSuccess) { goto loser;
}
/* There should be nothing left to read. */ if (SSL_READER_REMAINING(&rdr) > 0) { goto loser;
}
/* Sets |*certVerifyAlg| to the expected_cert_verify_algorithm field from the * serialized DC |in|. Returns SECSuccess upon success; SECFailure indicates a * decoding failure or the input wasn't long enough.
*/ static SECStatus
tls13_GetExpectedCertVerifyAlg(SECItem in, SSLSignatureScheme *certVerifyAlg)
{
SECStatus rv;
PRUint64 n;
sslReader rdr = SSL_READER(in.data, in.len);
if (in.len < 6) { /* Buffer too short to contain the first two params. */ return SECFailure;
}
/* Returns PR_TRUE if the host is verifying the handshake with a DC. */
PRBool
tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss)
{ /* We currently do not support client-delegated credentials. */ if (ss->sec.isServer ||
!ss->opt.enableDelegatedCredentials ||
!ss->xtnData.peerDelegCred) { return PR_FALSE;
}
return PR_TRUE;
}
/* Returns PR_TRUE if the host is signing the handshake with a DC. */
PRBool
tls13_IsSigningWithDelegatedCredential(const sslSocket *ss)
{ if (!ss->sec.isServer ||
!ss->xtnData.sendingDelegCredToPeer ||
!ss->xtnData.peerRequestedDelegCred) { return PR_FALSE;
}
return PR_TRUE;
}
/* Commits to authenticating with a DC if all of the following conditions hold: * - the negotiated protocol is TLS 1.3 or newer; * - the selected certificate has a DC configured; * - the peer has indicated support for this extension; * - the peer has indicated support for the DC signature scheme; and * - the host supports the DC signature scheme. * * It's the caller's responsibility to ensure that the version has been * negotiated and the certificate has been selected.
*/
SECStatus
tls13_MaybeSetDelegatedCredential(sslSocket *ss)
{
SECStatus rv;
PRBool doesRsaPss;
SECKEYPrivateKey *priv;
SSLSignatureScheme scheme;
/* Assert that the host is the server (we do not currently support * client-delegated credentials), the certificate has been * chosen, TLS 1.3 or higher has been negotiated, and that the set of * signature schemes supported by the client is known.
*/
PORT_Assert(ss->sec.isServer);
PORT_Assert(ss->sec.serverCert);
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
PORT_Assert(ss->xtnData.peerRequestedDelegCred == !!ss->xtnData.delegCredSigSchemes);
/* Check that the peer has indicated support and that a DC has been * configured for the selected certificate.
*/ if (!ss->xtnData.peerRequestedDelegCred ||
!ss->xtnData.delegCredSigSchemes ||
!ss->sec.serverCert->delegCred.len ||
!ss->sec.serverCert->delegCredKeyPair) { return SECSuccess;
}
/* Check that the host and peer both support the signing algorithm used with * the DC.
*/
rv = tls13_GetExpectedCertVerifyAlg(ss->sec.serverCert->delegCred,
&scheme); if (rv != SECSuccess) { return SECFailure;
}
/* Commit to sending a DC and set the handshake signature scheme to the * indicated algorithm.
*/
ss->xtnData.sendingDelegCredToPeer = PR_TRUE;
ss->ssl3.hs.signatureScheme = scheme; return SECSuccess;
}
/* Serializes the DC up to the signature. */ static SECStatus
tls13_AppendCredentialParams(sslBuffer *buf, sslDelegatedCredential *dc)
{
SECStatus rv;
rv = sslBuffer_AppendNumber(buf, dc->validTime, 4); if (rv != SECSuccess) { return SECFailure; /* Error set by caller. */
}
/* Serialize the DC parameters. */
rv = tls13_AppendCredentialParams(&dcBuf, dc); if (rv != SECSuccess) { goto loser; /* Error set by caller. */
}
/* Hash the message that was signed by the delegator. */
rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf); if (rv != SECSuccess) {
FATAL_ERROR(ss, PORT_GetError(), internal_error); goto loser;
}
/* The certificate must have the delegationUsage extension that authorizes * it to negotiate delegated credentials.
*/
found = PR_FALSE; for (i = 0; cert->extensions[i] != NULL; i++) {
ext = cert->extensions[i]; if (SECITEM_CompareItem(&ext->id, &delegUsageOid) == SECEqual) {
found = PR_TRUE; break;
}
}
/* The certificate must also have the digitalSignature keyUsage set. */ if (!found ||
!cert->keyUsagePresent ||
!(cert->keyUsage & KU_DIGITAL_SIGNATURE)) {
FATAL_ERROR(ss, SSL_ERROR_DC_INVALID_KEY_USAGE, illegal_parameter); return SECFailure;
}
end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC);
now = ssl_Time(ss); if (now > end || end < 0) {
FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter); return SECFailure;
}
/* Not more than 7 days remaining in the validity period. */ if (end - now > kMaxDcValidity) {
FATAL_ERROR(ss, SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, illegal_parameter); return SECFailure;
}
return SECSuccess;
}
/* Returns SECSucces if |dc| is a DC for the current handshake; otherwise it * returns SECFailure. A valid DC meets three requirements: (1) the signature * was produced by the peer's end-entity certificate, (2) the end-entity * certificate must have the correct key usage, and (3) the DC must not be * expired and its remaining TTL must be <= the maximum validity period (fixed * as 7 days). * * This function calls FATAL_ERROR() when an error occurs.
*/
SECStatus
tls13_VerifyDelegatedCredential(sslSocket *ss,
sslDelegatedCredential *dc)
{
SECStatus rv;
PRTime start;
PRExplodedTime end;
CERTCertificate *cert = ss->sec.peerCert; char endStr[256];
static CERTSubjectPublicKeyInfo *
tls13_MakeDcSpki(const SECKEYPublicKey *dcPub, SSLSignatureScheme dcCertVerifyAlg)
{ switch (SECKEY_GetPublicKeyType(dcPub)) { case rsaKey: {
SECOidTag hashOid; switch (dcCertVerifyAlg) { /* Note: RSAE schemes are NOT permitted within DC SPKIs. However, * support for their issuance remains so as to enable negative
* testing of client behavior. */ case ssl_sig_rsa_pss_rsae_sha256: case ssl_sig_rsa_pss_rsae_sha384: case ssl_sig_rsa_pss_rsae_sha512: return SECKEY_CreateSubjectPublicKeyInfo(dcPub); case ssl_sig_rsa_pss_pss_sha256:
hashOid = SEC_OID_SHA256; break; case ssl_sig_rsa_pss_pss_sha384:
hashOid = SEC_OID_SHA384; break; case ssl_sig_rsa_pss_pss_sha512:
hashOid = SEC_OID_SHA512; break;
/* Returns a serialized DC with the given parameters. * * Note that this function is meant primarily for testing. In particular, it * DOES NOT verify any of the following: * - |certPriv| is the private key corresponding to |cert|; * - that |checkCertKeyUsage(cert) == SECSuccess|; * - |dcValidFor| is less than 7 days (the maximum permitted by the spec); or * - validTime doesn't overflow a PRUint32. * * These conditions are things we want to test for, which is why we allow them * here. A real API for creating DCs would want to explicitly check ALL of these * conditions are met.
*/
SECStatus
SSLExp_DelegateCredential(const CERTCertificate *cert, const SECKEYPrivateKey *certPriv, const SECKEYPublicKey *dcPub,
SSLSignatureScheme dcCertVerifyAlg,
PRUint32 dcValidFor,
PRTime now,
SECItem *out)
{
SECStatus rv;
SSL3Hashes hash;
CERTSubjectPublicKeyInfo *spki = NULL;
SECKEYPrivateKey *tmpPriv = NULL;
sslDelegatedCredential *dc = NULL;
sslBuffer dcBuf = SSL_BUFFER_EMPTY;
if (dc->alg == ssl_sig_none) {
SECOidTag spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); /* If the Cert SPKI contained an AlgorithmIdentifier of "rsaEncryption", set a * default rsa_pss_rsae_sha256 scheme. NOTE: RSAE SPKIs are not permitted within * "real" Delegated Credentials. However, since this function is primarily used for * testing, we retain this support in order to verify that these DCs are rejected
* by tls13_VerifyDelegatedCredential. */ if (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION) {
SSLSignatureScheme scheme = ssl_sig_rsa_pss_rsae_sha256; if (ssl_SignatureSchemeValid(scheme, spkiOid, PR_TRUE /* isTls13 */)) {
dc->alg = scheme;
}
}
}
PORT_Assert(dc->alg != ssl_sig_none);
/* Sign the hash with the delegation key. * * The PK11 API discards const qualifiers, so we have to make a copy of * |certPriv| and pass the copy to |ssl3_SignHashesWithPrivKey|.
*/
tmpPriv = SECKEY_CopyPrivateKey(certPriv);
rv = ssl3_SignHashesWithPrivKey(&hash, tmpPriv, dc->alg,
PR_TRUE /* isTls */, &dc->signature); if (rv != SECSuccess) { goto loser;
}
/* Serialize the DC signature. */
rv = tls13_AppendCredentialSignature(&dcBuf, dc); if (rv != SECSuccess) { goto loser;
}
/* Copy the serialized DC to |out|. */
rv = SECITEM_MakeItem(NULL, out, dcBuf.buf, dcBuf.len); if (rv != SECSuccess) { goto loser;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.