2 // SecSignatureVerificationSupport.c
6 #include <TargetConditionals.h>
7 #include <AssertMacros.h>
8 #include <Security/SecSignatureVerificationSupport.h>
10 #include <CoreFoundation/CFString.h>
11 #include <utilities/SecCFError.h>
12 #include <utilities/SecCFWrappers.h>
14 #include <Security/SecBasePriv.h>
15 #include <Security/SecKey.h>
16 #include <Security/SecKeyPriv.h>
17 #include <Security/SecECKeyPriv.h>
19 #include <corecrypto/ccn.h>
20 #include <corecrypto/ccec.h>
21 #include <corecrypto/ccder.h>
23 static const uint8_t *sec_decode_forced_uint(cc_size n
,
24 cc_unit
*r
, const uint8_t *der
, const uint8_t *der_end
)
27 der
= ccder_decode_tl(CCDER_INTEGER
, &len
, der
, der_end
);
28 if (der
&& ccn_read_uint(n
, r
, len
, der
) >= 0) {
35 SecCreateSignatureVerificationError(OSStatus errorCode
, CFStringRef descriptionString
)
37 const CFStringRef defaultDescription
= CFSTR("Error verifying signature.");
38 const void* keys
[1] = { kCFErrorDescriptionKey
};
39 const void* values
[2] = { (descriptionString
) ? descriptionString
: defaultDescription
};
40 return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault
,
41 kCFErrorDomainOSStatus
, errorCode
, keys
, values
, 1);
45 SecRecreateSignatureWithAlgId(SecKeyRef publicKey
, const SecAsn1AlgId
*publicKeyAlgId
,
46 const uint8_t *oldSignature
, size_t oldSignatureSize
,
47 uint8_t **newSignature
, size_t *newSignatureSize
)
49 if (!publicKey
|| !publicKeyAlgId
||
50 kSecECDSAAlgorithmID
!= SecKeyGetAlgorithmId(publicKey
)) {
51 // ECDSA SHA-256 is the only type of signature currently supported by this function
55 cc_size n
= ccec_cp_n(ccec_cp_256());
58 const uint8_t *oldSignatureEnd
= oldSignature
+ oldSignatureSize
;
60 oldSignature
= ccder_decode_sequence_tl(&oldSignatureEnd
, oldSignature
, oldSignatureEnd
);
61 oldSignature
= sec_decode_forced_uint(n
, r
, oldSignature
, oldSignatureEnd
);
62 oldSignature
= sec_decode_forced_uint(n
, s
, oldSignature
, oldSignatureEnd
);
63 if (!oldSignature
|| !(oldSignatureEnd
== oldSignature
)) {
64 // failed to decode the old signature successfully
69 const uint8_t *outputPointer
= *newSignature
;
70 uint8_t *outputEndPointer
= *newSignature
+ *newSignatureSize
;
72 *newSignature
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
,
73 outputEndPointer
, outputPointer
,
74 ccder_encode_integer(n
, r
, outputPointer
, ccder_encode_integer(n
, s
, outputPointer
, outputEndPointer
)));
75 long newSigSize
= outputEndPointer
- *newSignature
;
76 *newSignatureSize
= (newSigSize
>= 0) ? (size_t)newSigSize
: 0;
79 bool SecVerifySignatureWithPublicKey(SecKeyRef publicKey
, const SecAsn1AlgId
*publicKeyAlgId
,
80 const uint8_t *dataToHash
, size_t amountToHash
,
81 const uint8_t *signatureStart
, size_t signatureSize
,
84 OSStatus errorCode
= errSecParam
;
85 require(signatureSize
> 0, fail
);
87 errorCode
= SecKeyDigestAndVerify(publicKey
, publicKeyAlgId
,
88 dataToHash
, amountToHash
,
89 (uint8_t*)signatureStart
, signatureSize
);
90 require_noerr(errorCode
, fail
);
94 ; // Semicolon works around compiler issue that won't recognize a declaration directly after a label
96 // fallback to potentially fix signatures with missing zero-byte padding.
97 // worst-case is that both integers get zero-padded, plus size of each integer and sequence size increases by 1
98 size_t replacementSignatureLen
= signatureSize
+ 5;
99 uint8_t *replacementSignature
= malloc(replacementSignatureLen
);
100 require_quiet(replacementSignature
, fail2
);
102 uint8_t *replacementSignaturePtr
= replacementSignature
;
103 SecRecreateSignatureWithAlgId(publicKey
, publicKeyAlgId
, signatureStart
, signatureSize
, &replacementSignaturePtr
, &replacementSignatureLen
);
104 require_quiet(replacementSignaturePtr
, fail2
);
106 require_noerr_quiet(SecKeyDigestAndVerify(publicKey
, publicKeyAlgId
, dataToHash
, amountToHash
, replacementSignaturePtr
, replacementSignatureLen
), fail2
);
108 free(replacementSignature
);
112 if (replacementSignature
) {
113 free(replacementSignature
);
116 *error
= SecCreateSignatureVerificationError(errorCode
, CFSTR("Unable to verify signature"));