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);
44 #pragma clang diagnostic push
45 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
47 SecRecreateSignatureWithAlgId(SecKeyRef publicKey
, const SecAsn1AlgId
*publicKeyAlgId
,
48 const uint8_t *oldSignature
, size_t oldSignatureSize
,
49 uint8_t **newSignature
, size_t *newSignatureSize
)
50 #pragma clang diagnostic pop
52 if (!publicKey
|| !publicKeyAlgId
||
53 kSecECDSAAlgorithmID
!= SecKeyGetAlgorithmId(publicKey
)) {
54 // ECDSA SHA-256 is the only type of signature currently supported by this function
58 cc_size n
= ccec_cp_n(ccec_cp_256());
61 const uint8_t *oldSignatureEnd
= oldSignature
+ oldSignatureSize
;
63 oldSignature
= ccder_decode_sequence_tl(&oldSignatureEnd
, oldSignature
, oldSignatureEnd
);
64 oldSignature
= sec_decode_forced_uint(n
, r
, oldSignature
, oldSignatureEnd
);
65 oldSignature
= sec_decode_forced_uint(n
, s
, oldSignature
, oldSignatureEnd
);
66 if (!oldSignature
|| !(oldSignatureEnd
== oldSignature
)) {
67 // failed to decode the old signature successfully
72 const uint8_t *outputPointer
= *newSignature
;
73 uint8_t *outputEndPointer
= *newSignature
+ *newSignatureSize
;
75 *newSignature
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
,
76 outputEndPointer
, outputPointer
,
77 ccder_encode_integer(n
, r
, outputPointer
, ccder_encode_integer(n
, s
, outputPointer
, outputEndPointer
)));
78 long newSigSize
= outputEndPointer
- *newSignature
;
79 *newSignatureSize
= (newSigSize
>= 0) ? (size_t)newSigSize
: 0;
82 #pragma clang diagnostic push
83 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
84 bool SecVerifySignatureWithPublicKey(SecKeyRef publicKey
, const SecAsn1AlgId
*publicKeyAlgId
,
85 const uint8_t *dataToHash
, size_t amountToHash
,
86 const uint8_t *signatureStart
, size_t signatureSize
,
88 #pragma clang diagnostic pop
90 OSStatus errorCode
= errSecParam
;
91 require(signatureSize
> 0, fail
);
93 errorCode
= SecKeyDigestAndVerify(publicKey
, publicKeyAlgId
,
94 dataToHash
, amountToHash
,
95 (uint8_t*)signatureStart
, signatureSize
);
96 require_noerr_quiet(errorCode
, fail
);
100 ; // Semicolon works around compiler issue that won't recognize a declaration directly after a label
102 // fallback to potentially fix signatures with missing zero-byte padding.
103 // worst-case is that both integers get zero-padded, plus size of each integer and sequence size increases by 1
104 size_t replacementSignatureLen
= signatureSize
+ 5;
105 uint8_t *replacementSignature
= malloc(replacementSignatureLen
);
106 require_quiet(replacementSignature
, fail2
);
108 uint8_t *replacementSignaturePtr
= replacementSignature
;
109 SecRecreateSignatureWithAlgId(publicKey
, publicKeyAlgId
, signatureStart
, signatureSize
, &replacementSignaturePtr
, &replacementSignatureLen
);
110 require_quiet(replacementSignaturePtr
, fail2
);
112 require_noerr_quiet(SecKeyDigestAndVerify(publicKey
, publicKeyAlgId
, dataToHash
, amountToHash
, replacementSignaturePtr
, replacementSignatureLen
), fail2
);
114 free(replacementSignature
);
118 if (replacementSignature
) {
119 free(replacementSignature
);
122 *error
= SecCreateSignatureVerificationError(errorCode
, CFSTR("Unable to verify signature"));