|
Packit |
40b132 |
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
Packit |
40b132 |
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
Packit |
40b132 |
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
Packit |
40b132 |
*/
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
#include "pkcs1sig.h"
|
|
Packit |
40b132 |
#include "hasht.h"
|
|
Packit |
40b132 |
#include "secerr.h"
|
|
Packit |
40b132 |
#include "secasn1t.h"
|
|
Packit |
40b132 |
#include "secoid.h"
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
typedef struct pkcs1PrefixStr pkcs1Prefix;
|
|
Packit |
40b132 |
struct pkcs1PrefixStr {
|
|
Packit |
40b132 |
unsigned int len;
|
|
Packit |
40b132 |
PRUint8 *data;
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
typedef struct pkcs1PrefixesStr pkcs1Prefixes;
|
|
Packit |
40b132 |
struct pkcs1PrefixesStr {
|
|
Packit |
40b132 |
unsigned int digestLen;
|
|
Packit |
40b132 |
pkcs1Prefix prefixWithParams;
|
|
Packit |
40b132 |
pkcs1Prefix prefixWithoutParams;
|
|
Packit |
40b132 |
};
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
/* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on
|
|
Packit |
40b132 |
* the possible prefix encodings as explained below.
|
|
Packit |
40b132 |
*/
|
|
Packit |
40b132 |
#define MAX_PREFIX_LEN_EXCLUDING_OID 10
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
static SECStatus
|
|
Packit |
40b132 |
encodePrefix(const SECOidData *hashOid, unsigned int digestLen,
|
|
Packit |
40b132 |
pkcs1Prefix *prefix, PRBool withParams)
|
|
Packit |
40b132 |
{
|
|
Packit |
40b132 |
/* with params coding is:
|
|
Packit |
40b132 |
* Sequence (2 bytes) {
|
|
Packit |
40b132 |
* Sequence (2 bytes) {
|
|
Packit |
40b132 |
* Oid (2 bytes) {
|
|
Packit |
40b132 |
* Oid value (derOid->oid.len)
|
|
Packit |
40b132 |
* }
|
|
Packit |
40b132 |
* NULL (2 bytes)
|
|
Packit |
40b132 |
* }
|
|
Packit |
40b132 |
* OCTECT (2 bytes);
|
|
Packit |
40b132 |
*
|
|
Packit |
40b132 |
* without params coding is:
|
|
Packit |
40b132 |
* Sequence (2 bytes) {
|
|
Packit |
40b132 |
* Sequence (2 bytes) {
|
|
Packit |
40b132 |
* Oid (2 bytes) {
|
|
Packit |
40b132 |
* Oid value (derOid->oid.len)
|
|
Packit |
40b132 |
* }
|
|
Packit |
40b132 |
* }
|
|
Packit |
40b132 |
* OCTECT (2 bytes);
|
|
Packit |
40b132 |
*/
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
unsigned int innerSeqLen = 2 + hashOid->oid.len;
|
|
Packit |
40b132 |
unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen;
|
|
Packit |
40b132 |
unsigned int extra = 0;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (withParams) {
|
|
Packit |
40b132 |
innerSeqLen += 2;
|
|
Packit |
40b132 |
outerSeqLen += 2;
|
|
Packit |
40b132 |
extra = 2;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (innerSeqLen >= 128 ||
|
|
Packit |
40b132 |
outerSeqLen >= 128 ||
|
|
Packit |
40b132 |
(outerSeqLen + 2 - digestLen) >
|
|
Packit |
40b132 |
(MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) {
|
|
Packit |
40b132 |
/* this is actually a library failure, It shouldn't happen */
|
|
Packit |
40b132 |
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
Packit |
40b132 |
return SECFailure;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
prefix->len = 6 + hashOid->oid.len + extra + 2;
|
|
Packit |
40b132 |
prefix->data = PORT_Alloc(prefix->len);
|
|
Packit |
40b132 |
if (!prefix->data) {
|
|
Packit |
40b132 |
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
Packit |
40b132 |
return SECFailure;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
prefix->data[0] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
|
|
Packit |
40b132 |
prefix->data[1] = outerSeqLen;
|
|
Packit |
40b132 |
prefix->data[2] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
|
|
Packit |
40b132 |
prefix->data[3] = innerSeqLen;
|
|
Packit |
40b132 |
prefix->data[4] = SEC_ASN1_OBJECT_ID;
|
|
Packit |
40b132 |
prefix->data[5] = hashOid->oid.len;
|
|
Packit |
40b132 |
PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len);
|
|
Packit |
40b132 |
if (withParams) {
|
|
Packit |
40b132 |
prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL;
|
|
Packit |
40b132 |
prefix->data[6 + hashOid->oid.len + 1] = 0;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING;
|
|
Packit |
40b132 |
prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
return SECSuccess;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
SECStatus
|
|
Packit |
40b132 |
_SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
|
|
Packit |
40b132 |
const SECItem* digest,
|
|
Packit |
40b132 |
const SECItem* dataRecoveredFromSignature,
|
|
Packit |
40b132 |
PRBool unsafeAllowMissingParameters)
|
|
Packit |
40b132 |
{
|
|
Packit |
40b132 |
SECOidData *hashOid;
|
|
Packit |
40b132 |
pkcs1Prefixes pp;
|
|
Packit |
40b132 |
const pkcs1Prefix* expectedPrefix;
|
|
Packit |
40b132 |
SECStatus rv, rv2, rv3;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (!digest || !digest->data ||
|
|
Packit |
40b132 |
!dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
|
|
Packit |
40b132 |
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
Packit |
40b132 |
return SECFailure;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
hashOid = SECOID_FindOIDByTag(digestAlg);
|
|
Packit |
40b132 |
if (hashOid == NULL) {
|
|
Packit |
40b132 |
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
Packit |
40b132 |
return SECFailure;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
pp.digestLen = digest->len;
|
|
Packit |
40b132 |
pp.prefixWithParams.data = NULL;
|
|
Packit |
40b132 |
pp.prefixWithoutParams.data = NULL;
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE);
|
|
Packit |
40b132 |
rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE);
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
rv = SECSuccess;
|
|
Packit |
40b132 |
if (rv2 != SECSuccess || rv3 != SECSuccess) {
|
|
Packit |
40b132 |
rv = SECFailure;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (rv == SECSuccess) {
|
|
Packit |
40b132 |
/* We don't attempt to avoid timing attacks on these comparisons because
|
|
Packit |
40b132 |
* signature verification is a public key operation, not a private key
|
|
Packit |
40b132 |
* operation.
|
|
Packit |
40b132 |
*/
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (dataRecoveredFromSignature->len ==
|
|
Packit |
40b132 |
pp.prefixWithParams.len + pp.digestLen) {
|
|
Packit |
40b132 |
expectedPrefix = &pp.prefixWithParams;
|
|
Packit |
40b132 |
} else if (unsafeAllowMissingParameters &&
|
|
Packit |
40b132 |
dataRecoveredFromSignature->len ==
|
|
Packit |
40b132 |
pp.prefixWithoutParams.len + pp.digestLen) {
|
|
Packit |
40b132 |
expectedPrefix = &pp.prefixWithoutParams;
|
|
Packit |
40b132 |
} else {
|
|
Packit |
40b132 |
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
|
|
Packit |
40b132 |
rv = SECFailure;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (rv == SECSuccess) {
|
|
Packit |
40b132 |
if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data,
|
|
Packit |
40b132 |
expectedPrefix->len) ||
|
|
Packit |
40b132 |
memcmp(dataRecoveredFromSignature->data + expectedPrefix->len,
|
|
Packit |
40b132 |
digest->data, digest->len)) {
|
|
Packit |
40b132 |
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
|
|
Packit |
40b132 |
rv = SECFailure;
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
if (pp.prefixWithParams.data) {
|
|
Packit |
40b132 |
PORT_Free(pp.prefixWithParams.data);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
if (pp.prefixWithoutParams.data) {
|
|
Packit |
40b132 |
PORT_Free(pp.prefixWithoutParams.data);
|
|
Packit |
40b132 |
}
|
|
Packit |
40b132 |
|
|
Packit |
40b132 |
return rv;
|
|
Packit |
40b132 |
}
|