SecSignatureVerificationSupport.c
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 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) 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 34 static CFErrorRef 35 SecCreateSignatureVerificationError(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 44 #pragma clang diagnostic push 45 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 46 static void 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 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 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, 87 CFErrorRef *error) 88 #pragma clang diagnostic pop 89 { 90 OSStatus errorCode = errSecParam; 91 require(signatureSize > 0, fail); 92 93 errorCode = SecKeyDigestAndVerify(publicKey, publicKeyAlgId, 94 dataToHash, amountToHash, 95 (uint8_t*)signatureStart, signatureSize); 96 require_noerr_quiet(errorCode, fail); 97 return true; 98 99 fail: 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 117 fail2: 118 if (replacementSignature) { 119 free(replacementSignature); 120 } 121 if (error) { 122 *error = SecCreateSignatureVerificationError(errorCode, CFSTR("Unable to verify signature")); 123 } 124 return false; 125 }