Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* TLS 1.3 Protocol
*
* 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/. */
#include "sslimpl.h"
#include "cryptohi.h"
#include "keyhi.h"
/* we put this here because it only affects TLS 1.3, and not TLS 1.2 and earlier
* which use the old sign hashes interface. The TLS 1.3 protocol is friendly to
* algorthims that don't have a signed hashes interface */
/* we generate an algorithm ID rather than just use an OID to support RSAPSS.
* It's generated completely from the scheme */
static SECAlgorithmID *
tls_GetSignatureAlgorithmId(PLArenaPool *arena, SSLSignatureScheme scheme,
SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey)
{
SECAlgorithmID *newAlgID = PORT_ArenaZNew(arena, SECAlgorithmID);
SECOidTag algTag = SEC_OID_UNKNOWN;
SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
SECStatus rv;
switch (scheme) {
/* For the algTag the difference between rsa_pss_rsae and
* rsa_pss_pss is in the selection of the cert.
* At this stage, the signatures are the same, so for our
* purposed they are equivalent */
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_pss_sha256:
algTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
hashAlgTag = SEC_OID_SHA256;
break;
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_pss_sha384:
algTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
hashAlgTag = SEC_OID_SHA384;
break;
case ssl_sig_rsa_pss_rsae_sha512:
case ssl_sig_rsa_pss_pss_sha512:
algTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
hashAlgTag = SEC_OID_SHA512;
break;
/* the curve comes from the key and should have already been
* enforced at a different level */
case ssl_sig_ecdsa_secp256r1_sha256:
algTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
hashAlgTag = SEC_OID_SHA256;
break;
case ssl_sig_ecdsa_secp384r1_sha384:
algTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE;
hashAlgTag = SEC_OID_SHA384;
break;
case ssl_sig_ecdsa_secp521r1_sha512:
algTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE;
hashAlgTag = SEC_OID_SHA512;
break;
/* the following is unsupported in tls 1.3 and greater, just break.
* We include them here explicitly so we get the compiler warning about
* missing enums in the switch statement. default would be a break anyway.
* That way we'll know to update this table when new algorithms are
* added */
/* as of now edward curve signatures are not supported in NSS. That
* could change, and this is part the code that would pick up the
* change (need OIDS for the hash variants of these signature, and
* then add them here) */
case ssl_sig_ed25519:
case ssl_sig_ed448:
/* sha1 hashes in sigs are explicitly disallowed in TLS 1.3 or greater */
case ssl_sig_ecdsa_sha1:
/* rsa pkcs1 sigs are explicitly disallowed in TLS 1.3 and greater */
case ssl_sig_rsa_pkcs1_sha1:
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
/* dsa sigs are explicitly disallowed in TLS 1.3 and greater */
case ssl_sig_dsa_sha1:
case ssl_sig_dsa_sha256:
case ssl_sig_dsa_sha384:
case ssl_sig_dsa_sha512:
/* special sig variants that aren't supported in TLS 1.3 or greater */
case ssl_sig_rsa_pkcs1_sha1md5:
case ssl_sig_none:
break;
}
/* the earlier code should have made sure none of the unsupported
* algorithms were accepted */
PORT_Assert(algTag != SEC_OID_UNKNOWN);
if (algTag == SEC_OID_UNKNOWN) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL;
}
/* now get the algorithm ID algTag will override whatever is normally
* selected from the key */
rv = SEC_CreateSignatureAlgorithmID(arena, newAlgID, algTag, hashAlgTag,
NULL, privKey, pubKey);
if (rv != SECSuccess) {
return NULL;
}
return newAlgID;
}
tlsSignOrVerifyContext
tls_CreateSignOrVerifyContext(SECKEYPrivateKey *privKey,
SECKEYPublicKey *pubKey,
SSLSignatureScheme scheme, sslSignOrVerify type,
SECItem *signature, void *pwArg)
{
PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
tlsSignOrVerifyContext newCtx = { type, { NULL } };
SECStatus rv;
if (!arena) {
goto loser;
}
if (type == sig_sign) {
PORT_Assert(privKey);
} else {
PORT_Assert(pubKey);
}
/* we use sigAlgID here because it automatically formats parameters
* for PSS. */
SECAlgorithmID *sigAlgID = tls_GetSignatureAlgorithmId(arena, scheme,
privKey, pubKey);
if (sigAlgID == NULL) {
goto loser;
}
if (type == sig_sign) {
newCtx.u.sig = SGN_NewContextWithAlgorithmID(sigAlgID, privKey);
if (!newCtx.u.sig) {
goto loser;
}
rv = SGN_Begin(newCtx.u.sig);
} else {
newCtx.u.vfy = VFY_CreateContextWithAlgorithmID(pubKey, signature,
sigAlgID, NULL, pwArg);
if (!newCtx.u.vfy) {
goto loser;
}
rv = VFY_Begin(newCtx.u.vfy);
}
if (rv != SECSuccess) {
goto loser;
}
PORT_FreeArena(arena, PR_FALSE);
return newCtx;
loser:
tls_DestroySignOrVerifyContext(newCtx);
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
return newCtx; /* pointer already set to NULL by destroy */
}
SECStatus
tls_SignOrVerifyUpdate(tlsSignOrVerifyContext ctx, const unsigned char *buf,
int len)
{
SECStatus rv;
if (ctx.type == sig_sign) {
rv = SGN_Update(ctx.u.sig, buf, len);
} else {
rv = VFY_Update(ctx.u.vfy, buf, len);
}
return rv;
}
SECStatus
tls_SignOrVerifyEnd(tlsSignOrVerifyContext ctx, SECItem *sig)
{
SECStatus rv;
if (ctx.type == sig_sign) {
rv = SGN_End(ctx.u.sig, sig);
} else {
/* sig was already set in the context VFY_CreateContext */
rv = VFY_End(ctx.u.vfy);
}
/* destroy the context on success */
if (rv == SECSuccess) {
tls_DestroySignOrVerifyContext(ctx);
}
return rv;
}
void
tls_DestroySignOrVerifyContext(tlsSignOrVerifyContext ctx)
{
if (ctx.type == sig_sign) {
if (ctx.u.sig) {
SGN_DestroyContext(ctx.u.sig, PR_TRUE);
}
} else {
if (ctx.u.vfy) {
VFY_DestroyContext(ctx.u.vfy, PR_TRUE);
}
}
}