]> git.saurik.com Git - apple/security.git/blame - OSX/sec/Security/SecSignatureVerificationSupport.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / Security / SecSignatureVerificationSupport.c
CommitLineData
fa7225c8
A
1//
2// SecSignatureVerificationSupport.c
3// sec
4//
5
6#include <TargetConditionals.h>
7#include <AssertMacros.h>
8#include <Security/SecSignatureVerificationSupport.h>
9
10#include <CoreFoundation/CFString.h>
11#include <utilities/SecCFError.h>
12#include <utilities/SecCFWrappers.h>
13
14#include <Security/SecBasePriv.h>
15#include <Security/SecKey.h>
16#include <Security/SecKeyPriv.h>
17#include <Security/SecECKeyPriv.h>
18
19#include <corecrypto/ccn.h>
20#include <corecrypto/ccec.h>
21#include <corecrypto/ccder.h>
22
23static const uint8_t *sec_decode_forced_uint(cc_size n,
24 cc_unit *r, const uint8_t *der, const uint8_t *der_end)
25{
26 size_t len;
27 der = ccder_decode_tl(CCDER_INTEGER, &len, der, der_end);
28 if (der && ccn_read_uint(n, r, len, der) >= 0) {
29 return der + len;
30 }
31 return NULL;
32}
33
34static CFErrorRef
35SecCreateSignatureVerificationError(OSStatus errorCode, CFStringRef descriptionString)
36{
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);
42}
43
b54c578e
A
44#pragma clang diagnostic push
45#pragma clang diagnostic ignored "-Wdeprecated-declarations"
fa7225c8
A
46static void
47SecRecreateSignatureWithAlgId(SecKeyRef publicKey, const SecAsn1AlgId *publicKeyAlgId,
48 const uint8_t *oldSignature, size_t oldSignatureSize,
49 uint8_t **newSignature, size_t *newSignatureSize)
b54c578e 50#pragma clang diagnostic pop
fa7225c8
A
51{
52 if (!publicKey || !publicKeyAlgId ||
53 kSecECDSAAlgorithmID != SecKeyGetAlgorithmId(publicKey)) {
54 // ECDSA SHA-256 is the only type of signature currently supported by this function
55 return;
56 }
57
58 cc_size n = ccec_cp_n(ccec_cp_256());
59 cc_unit r[n], s[n];
60
61 const uint8_t *oldSignatureEnd = oldSignature + oldSignatureSize;
62
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
68 *newSignature = NULL;
69 return;
70 }
71
72 const uint8_t *outputPointer = *newSignature;
73 uint8_t *outputEndPointer = *newSignature + *newSignatureSize;
74
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;
80}
81
b54c578e
A
82#pragma clang diagnostic push
83#pragma clang diagnostic ignored "-Wdeprecated-declarations"
fa7225c8
A
84bool SecVerifySignatureWithPublicKey(SecKeyRef publicKey, const SecAsn1AlgId *publicKeyAlgId,
85 const uint8_t *dataToHash, size_t amountToHash,
86 const uint8_t *signatureStart, size_t signatureSize,
87 CFErrorRef *error)
b54c578e 88#pragma clang diagnostic pop
fa7225c8
A
89{
90 OSStatus errorCode = errSecParam;
91 require(signatureSize > 0, fail);
92
93 errorCode = SecKeyDigestAndVerify(publicKey, publicKeyAlgId,
94 dataToHash, amountToHash,
95 (uint8_t*)signatureStart, signatureSize);
b54c578e 96 require_noerr_quiet(errorCode, fail);
fa7225c8
A
97 return true;
98
99fail:
100 ; // Semicolon works around compiler issue that won't recognize a declaration directly after a label
101
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);
107
108 uint8_t *replacementSignaturePtr = replacementSignature;
109 SecRecreateSignatureWithAlgId(publicKey, publicKeyAlgId, signatureStart, signatureSize, &replacementSignaturePtr, &replacementSignatureLen);
110 require_quiet(replacementSignaturePtr, fail2);
111
112 require_noerr_quiet(SecKeyDigestAndVerify(publicKey, publicKeyAlgId, dataToHash, amountToHash, replacementSignaturePtr, replacementSignatureLen), fail2);
113
114 free(replacementSignature);
115 return true;
116
117fail2:
118 if (replacementSignature) {
119 free(replacementSignature);
120 }
121 if (error) {
122 *error = SecCreateSignatureVerificationError(errorCode, CFSTR("Unable to verify signature"));
123 }
124 return false;
125}