pkcs1sig.c (4863B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 */ 5 6 #include "pkcs1sig.h" 7 #include "hasht.h" 8 #include "secerr.h" 9 #include "secasn1t.h" 10 #include "secoid.h" 11 12 typedef struct pkcs1PrefixStr pkcs1Prefix; 13 struct pkcs1PrefixStr { 14 unsigned int len; 15 PRUint8 *data; 16 }; 17 18 /* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on 19 * the possible prefix encodings as explained below. 20 */ 21 #define MAX_PREFIX_LEN_EXCLUDING_OID 10 22 23 static SECStatus 24 encodePrefix(const SECOidData *hashOid, unsigned int digestLen, 25 pkcs1Prefix *prefix, PRBool withParams) 26 { 27 /* with params coding is: 28 * Sequence (2 bytes) { 29 * Sequence (2 bytes) { 30 * Oid (2 bytes) { 31 * Oid value (derOid->oid.len) 32 * } 33 * NULL (2 bytes) 34 * } 35 * OCTECT (2 bytes); 36 * 37 * without params coding is: 38 * Sequence (2 bytes) { 39 * Sequence (2 bytes) { 40 * Oid (2 bytes) { 41 * Oid value (derOid->oid.len) 42 * } 43 * } 44 * OCTECT (2 bytes); 45 */ 46 47 unsigned int innerSeqLen = 2 + hashOid->oid.len; 48 unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen; 49 unsigned int extra = 0; 50 51 if (withParams) { 52 innerSeqLen += 2; 53 outerSeqLen += 2; 54 extra = 2; 55 } 56 57 if (innerSeqLen >= 128 || 58 outerSeqLen >= 128 || 59 (outerSeqLen + 2 - digestLen) > 60 (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) { 61 /* this is actually a library failure, It shouldn't happen */ 62 PORT_SetError(SEC_ERROR_INVALID_ARGS); 63 return SECFailure; 64 } 65 66 prefix->len = 6 + hashOid->oid.len + extra + 2; 67 prefix->data = PORT_Alloc(prefix->len); 68 if (!prefix->data) { 69 PORT_SetError(SEC_ERROR_NO_MEMORY); 70 return SECFailure; 71 } 72 73 prefix->data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED; 74 prefix->data[1] = outerSeqLen; 75 prefix->data[2] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED; 76 prefix->data[3] = innerSeqLen; 77 prefix->data[4] = SEC_ASN1_OBJECT_ID; 78 prefix->data[5] = hashOid->oid.len; 79 PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len); 80 if (withParams) { 81 prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL; 82 prefix->data[6 + hashOid->oid.len + 1] = 0; 83 } 84 prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING; 85 prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen; 86 87 return SECSuccess; 88 } 89 90 SECStatus 91 _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg, 92 const SECItem *digest, 93 const SECItem *dataRecoveredFromSignature, 94 PRBool unsafeAllowMissingParameters) 95 { 96 SECOidData *hashOid; 97 pkcs1Prefix prefix; 98 SECStatus rv; 99 100 if (!digest || !digest->data || 101 !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) { 102 PORT_SetError(SEC_ERROR_INVALID_ARGS); 103 return SECFailure; 104 } 105 106 hashOid = SECOID_FindOIDByTag(digestAlg); 107 if (hashOid == NULL) { 108 PORT_SetError(SEC_ERROR_INVALID_ARGS); 109 return SECFailure; 110 } 111 112 prefix.data = NULL; 113 114 rv = encodePrefix(hashOid, digest->len, &prefix, PR_TRUE); 115 116 if (rv == SECSuccess) { 117 /* We don't attempt to avoid timing attacks on these comparisons because 118 * signature verification is a public key operation, not a private key 119 * operation. 120 */ 121 122 if (dataRecoveredFromSignature->len != prefix.len + digest->len) { 123 PRBool lengthMismatch = PR_TRUE; 124 #ifdef NSS_PKCS1_AllowMissingParameters 125 if (unsafeAllowMissingParameters) { 126 if (prefix.data) { 127 PORT_Free(prefix.data); 128 prefix.data = NULL; 129 } 130 rv = encodePrefix(hashOid, digest->len, &prefix, PR_FALSE); 131 if (rv != SECSuccess || 132 dataRecoveredFromSignature->len == prefix.len + digest->len) { 133 lengthMismatch = PR_FALSE; 134 } 135 } 136 #endif 137 if (lengthMismatch) { 138 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 139 rv = SECFailure; 140 } 141 } 142 } 143 144 if (rv == SECSuccess) { 145 if (memcmp(dataRecoveredFromSignature->data, prefix.data, prefix.len) || 146 memcmp(dataRecoveredFromSignature->data + prefix.len, digest->data, 147 digest->len)) { 148 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 149 rv = SECFailure; 150 } 151 } 152 153 if (prefix.data) { 154 PORT_Free(prefix.data); 155 } 156 157 return rv; 158 }