|
@@ -23,7 +23,7 @@
|
|
@param siglen The length of the signature data (octets)
|
|
@param siglen The length of the signature data (octets)
|
|
@param hash The hash of the message that was signed
|
|
@param hash The hash of the message that was signed
|
|
@param hashlen The length of the hash of the message that was signed (octets)
|
|
@param hashlen The length of the hash of the message that was signed (octets)
|
|
- @param padding Type of padding (LTC_PKCS_1_PSS or LTC_PKCS_1_V1_5)
|
|
|
|
|
|
+ @param padding Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
|
|
@param hash_idx The index of the desired hash
|
|
@param hash_idx The index of the desired hash
|
|
@param saltlen The length of the salt used during signature
|
|
@param saltlen The length of the salt used during signature
|
|
@param stat [out] The result of the signature comparison, 1==valid, 0==invalid
|
|
@param stat [out] The result of the signature comparison, 1==valid, 0==invalid
|
|
@@ -51,11 +51,12 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
|
|
/* valid padding? */
|
|
/* valid padding? */
|
|
|
|
|
|
if ((padding != LTC_PKCS_1_V1_5) &&
|
|
if ((padding != LTC_PKCS_1_V1_5) &&
|
|
- (padding != LTC_PKCS_1_PSS)) {
|
|
|
|
|
|
+ (padding != LTC_PKCS_1_PSS) &&
|
|
|
|
+ (padding != LTC_PKCS_1_V1_5_NA1)) {
|
|
return CRYPT_PK_INVALID_PADDING;
|
|
return CRYPT_PK_INVALID_PADDING;
|
|
}
|
|
}
|
|
|
|
|
|
- if (padding == LTC_PKCS_1_PSS) {
|
|
|
|
|
|
+ if (padding != LTC_PKCS_1_V1_5_NA1) {
|
|
/* valid hash ? */
|
|
/* valid hash ? */
|
|
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
|
|
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
|
|
return err;
|
|
return err;
|
|
@@ -103,15 +104,8 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
|
|
} else {
|
|
} else {
|
|
/* PKCS #1 v1.5 decode it */
|
|
/* PKCS #1 v1.5 decode it */
|
|
unsigned char *out;
|
|
unsigned char *out;
|
|
- unsigned long outlen, loid[16], reallen;
|
|
|
|
|
|
+ unsigned long outlen;
|
|
int decoded;
|
|
int decoded;
|
|
- ltc_asn1_list digestinfo[2], siginfo[2];
|
|
|
|
-
|
|
|
|
- /* not all hashes have OIDs... so sad */
|
|
|
|
- if (hash_descriptor[hash_idx].OIDlen == 0) {
|
|
|
|
- err = CRYPT_INVALID_ARG;
|
|
|
|
- goto bail_2;
|
|
|
|
- }
|
|
|
|
|
|
|
|
/* allocate temp buffer for decoded hash */
|
|
/* allocate temp buffer for decoded hash */
|
|
outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3;
|
|
outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3;
|
|
@@ -126,37 +120,54 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
|
|
goto bail_2;
|
|
goto bail_2;
|
|
}
|
|
}
|
|
|
|
|
|
- /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
|
|
|
|
- /* construct the SEQUENCE
|
|
|
|
- SEQUENCE {
|
|
|
|
- SEQUENCE {hashoid OID
|
|
|
|
- blah NULL
|
|
|
|
- }
|
|
|
|
- hash OCTET STRING
|
|
|
|
|
|
+ if (padding == LTC_PKCS_1_V1_5) {
|
|
|
|
+ unsigned long loid[16], reallen;
|
|
|
|
+ ltc_asn1_list digestinfo[2], siginfo[2];
|
|
|
|
+
|
|
|
|
+ /* not all hashes have OIDs... so sad */
|
|
|
|
+ if (hash_descriptor[hash_idx].OIDlen == 0) {
|
|
|
|
+ err = CRYPT_INVALID_ARG;
|
|
|
|
+ goto bail_2;
|
|
}
|
|
}
|
|
- */
|
|
|
|
- LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0]));
|
|
|
|
- LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0);
|
|
|
|
- LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2);
|
|
|
|
- LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen);
|
|
|
|
-
|
|
|
|
- if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
|
|
|
|
- XFREE(out);
|
|
|
|
- goto bail_2;
|
|
|
|
- }
|
|
|
|
|
|
|
|
- if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) {
|
|
|
|
- XFREE(out);
|
|
|
|
- goto bail_2;
|
|
|
|
- }
|
|
|
|
|
|
+ /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
|
|
|
|
+ /* construct the SEQUENCE
|
|
|
|
+ SEQUENCE {
|
|
|
|
+ SEQUENCE {hashoid OID
|
|
|
|
+ blah NULL
|
|
|
|
+ }
|
|
|
|
+ hash OCTET STRING
|
|
|
|
+ }
|
|
|
|
+ */
|
|
|
|
+ LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0]));
|
|
|
|
+ LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0);
|
|
|
|
+ LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2);
|
|
|
|
+ LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen);
|
|
|
|
+
|
|
|
|
+ if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
|
|
|
|
+ XFREE(out);
|
|
|
|
+ goto bail_2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) {
|
|
|
|
+ XFREE(out);
|
|
|
|
+ goto bail_2;
|
|
|
|
+ }
|
|
|
|
|
|
- /* test OID */
|
|
|
|
- if ((reallen == outlen) &&
|
|
|
|
- (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
|
|
|
|
|
|
+ /* test OID */
|
|
|
|
+ if ((reallen == outlen) &&
|
|
|
|
+ (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
|
|
(XMEM_NEQ(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
|
|
(XMEM_NEQ(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
|
|
- (siginfo[1].size == hashlen) &&
|
|
|
|
|
|
+ (siginfo[1].size == hashlen) &&
|
|
(XMEM_NEQ(siginfo[1].data, hash, hashlen) == 0)) {
|
|
(XMEM_NEQ(siginfo[1].data, hash, hashlen) == 0)) {
|
|
- *stat = 1;
|
|
|
|
|
|
+ *stat = 1;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ /* only check if the hash is equal */
|
|
|
|
+ if ((hashlen == outlen) &&
|
|
|
|
+ (XMEMCMP(out, hash, hashlen) == 0)) {
|
|
|
|
+ *stat = 1;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef LTC_CLEAN_STACK
|
|
#ifdef LTC_CLEAN_STACK
|