From 406bd008b7ccaa62384db8e66b07df4e28927b5c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 16 May 2022 18:50:37 -0400 Subject: [PATCH] Make Darwin CHIPKeypair usable in a few more cases. (#18458) 1) Instead of having CHIPKeypair sign a digest, just have it sign a message. This tends to be more widely supported by cryptographic libraries. 2) Support the CHIPKeypair providing us either a raw SEC1 signature or an ASN.1 DER-encoded signature, since different cryptographic libraries may have different output signature formats. 3) Fix an incorrect comment in CHIPCryptoPAL.h. --- .../commands/common/CHIPToolKeypair.h | 2 +- .../commands/common/CHIPToolKeypair.mm | 4 +- src/crypto/CHIPCryptoPAL.h | 4 +- .../CHIPTool/Framework Helpers/FabricKeys.m | 4 +- src/darwin/Framework/CHIP/CHIPKeypair.h | 35 +++++++--- .../Framework/CHIP/CHIPP256KeypairBridge.mm | 64 ++++++++++++------- src/darwin/Framework/CHIPTests/CHIPTestKeys.m | 4 +- 7 files changed, 76 insertions(+), 41 deletions(-) diff --git a/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.h b/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.h index 272ee0b5517be7..b1721a612dedfb 100644 --- a/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.h +++ b/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.h @@ -4,7 +4,7 @@ @interface CHIPToolKeypair : NSObject - (BOOL)initialize; -- (NSData *)ECDSA_sign_hash:(NSData *)hash; +- (NSData *)ECDSA_sign_message_raw:(NSData *)message; - (SecKeyRef)pubkey; - (CHIP_ERROR)Serialize:(chip::Crypto::P256SerializedKeypair &)output; - (CHIP_ERROR)Deserialize:(chip::Crypto::P256SerializedKeypair &)input; diff --git a/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.mm b/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.mm index 234137195ffc21..6525a9d319dc2b 100644 --- a/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.mm +++ b/examples/chip-tool-darwin/commands/common/CHIPToolKeypair.mm @@ -33,11 +33,11 @@ - (BOOL)initialize return _mKeyPair.Initialize() == CHIP_NO_ERROR; } -- (NSData *)ECDSA_sign_hash:(NSData *)hash +- (NSData *)ECDSA_sign_message_raw:(NSData *)message { chip::Crypto::P256ECDSASignature signature; NSData * out_signature; - CHIP_ERROR signing_error = _mKeyPair.ECDSA_sign_hash((const uint8_t *) [hash bytes], (const size_t)[hash length], signature); + CHIP_ERROR signing_error = _mKeyPair.ECDSA_sign_msg((const uint8_t *) [message bytes], (size_t)[message length], signature); if (signing_error != CHIP_NO_ERROR) return nil; out_signature = [NSData dataWithBytes:signature.Bytes() length:signature.Length()]; diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 7c7ff382db99d6..41aea26aff09a4 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -537,8 +537,8 @@ CHIP_ERROR EcdsaRawSignatureToAsn1(size_t fe_length_bytes, const ByteSpan & raw_ * @param[in] fe_length_bytes Field Element length in bytes (e.g. 32 for P256 curve) * @param[in] asn1_sig ASN.1 DER signature input * @param[out] out_raw_sig Raw signature of concatenated format output buffer. Size must be at - * least >= `2 * fe_length_bytes`. On CHIP_NO_ERROR, the out_asn1_sig buffer will be re-assigned - * to have the correct size based on variable-length output. + * least >= `2 * fe_length_bytes`. On CHIP_NO_ERROR, the out_raw_sig buffer will be re-assigned + * to have the correct size (2 * fe_length_bytes). * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise */ CHIP_ERROR EcdsaAsn1SignatureToRaw(size_t fe_length_bytes, const ByteSpan & asn1_sig, MutableByteSpan & out_raw_sig); diff --git a/src/darwin/CHIPTool/CHIPTool/Framework Helpers/FabricKeys.m b/src/darwin/CHIPTool/CHIPTool/Framework Helpers/FabricKeys.m index 6b0eadd9f503a3..a2a9992d3180d7 100644 --- a/src/darwin/CHIPTool/CHIPTool/Framework Helpers/FabricKeys.m +++ b/src/darwin/CHIPTool/CHIPTool/Framework Helpers/FabricKeys.m @@ -207,11 +207,11 @@ - (instancetype)init return self; } -- (NSData *)ECDSA_sign_hash:(NSData *)hash +- (NSData *)ECDSA_sign_message_DER:(NSData *)message { CFErrorRef error = NULL; CFDataRef outData - = SecKeyCreateSignature(_privateKey, kSecKeyAlgorithmECDSASignatureRFC4754, (__bridge CFDataRef) hash, &error); + = SecKeyCreateSignature(_privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef) message, &error); if (error != noErr) { NSLog(@"Failed to sign cert: %@", (__bridge NSError *) error); diff --git a/src/darwin/Framework/CHIP/CHIPKeypair.h b/src/darwin/Framework/CHIP/CHIPKeypair.h index 5eb75e039587fb..87edc304fca33a 100644 --- a/src/darwin/Framework/CHIP/CHIPKeypair.h +++ b/src/darwin/Framework/CHIP/CHIPKeypair.h @@ -22,18 +22,37 @@ NS_ASSUME_NONNULL_BEGIN @protocol CHIPKeypair @required +/** + * @brief Return public key for the keypair. + */ +- (SecKeyRef)pubkey; +@optional /** - * @brief A function to sign a hash using ECDSA - * @param hash Hash that needs to be signed + * @brief A function to sign a message using ECDSA * - * @return Returns A signature that consists of: 2 EC elements (r and s), in raw point form (see SEC1). - **/ -- (NSData *)ECDSA_sign_hash:(NSData *)hash; + * @param message Message that needs to be signed + * + * @return A signature that consists of: 2 EC elements (r and s), in raw + * point form (see SEC1). Sometimes also called RFC 4754 form or P1363 + * form. + * + * Either this selector or ECDSA_sign_message_DER must be supported by a + * CHIPKeypair. + */ +- (NSData *)ECDSA_sign_message_raw:(NSData *)message; -/** @brief Return public key for the keypair. - **/ -- (SecKeyRef)pubkey; +/** + * @brief A function to sign a message using ECDSA + * + * @param message Message that needs to be signed + * + * @return An ASN.1 DER-encoded signature (per X9.62). + * + * Either this selector or ECDSA_sign_message_raw must be supported by a + * CHIPKeypair. + */ +- (NSData *)ECDSA_sign_message_DER:(NSData *)message; @end diff --git a/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm b/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm index 1d97909bfe6936..e9e5c2f055c31c 100644 --- a/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm +++ b/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm @@ -16,8 +16,8 @@ */ #import "CHIPP256KeypairBridge.h" +#import "NSDataSpanConversion.h" -#import #import #include @@ -28,6 +28,12 @@ CHIP_ERROR CHIPP256KeypairBridge::Init(id keypair) { + if (![keypair respondsToSelector:@selector(ECDSA_sign_message_DER:)] + && ![keypair respondsToSelector:@selector(ECDSA_sign_message_raw:)]) { + // Not a valid CHIPKeypair implementation. + return CHIP_ERROR_INVALID_ARGUMENT; + } + mKeypair = keypair; return setPubkey(); } @@ -76,20 +82,42 @@ return CHIP_ERROR_INCORRECT_STATE; } NSData * msgData = [NSData dataWithBytes:msg length:msg_length]; - NSMutableData * hashedData = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH]; - CC_SHA256(msgData.bytes, (CC_LONG) msgData.length, (unsigned char *) hashedData.mutableBytes); - CHIP_LOG_DEBUG("Generated Msg hash, signing hash now"); - NSData * signature = [mKeypair ECDSA_sign_hash:hashedData]; - if (!signature) { - CHIP_LOG_ERROR("ECDSA sign msg failure: no signature returned"); - return CHIP_ERROR_INTERNAL; + NSData * signature; + if ([mKeypair respondsToSelector:@selector(ECDSA_sign_message_DER:)]) { + signature = [mKeypair ECDSA_sign_message_DER:msgData]; + if (!signature) { + CHIP_LOG_ERROR("ECDSA sign msg failure: no signature returned"); + return CHIP_ERROR_INTERNAL; + } + + uint8_t buf[kP256_ECDSA_Signature_Length_Raw]; + chip::MutableByteSpan rawSignature(buf); + + CHIP_ERROR err = EcdsaAsn1SignatureToRaw(kP256_FE_Length, AsByteSpan(signature), rawSignature); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Converting ASN.1 DER signature to raw form failed: %s", chip::ErrorStr(err)); + return err; + } + + signature = AsData(rawSignature); + if (!signature) { + CHIP_LOG_ERROR("Failed to create NSData for raw signature"); + return CHIP_ERROR_INTERNAL; + } + } else { + signature = [mKeypair ECDSA_sign_message_raw:msgData]; + if (!signature) { + CHIP_LOG_ERROR("ECDSA sign msg failure: no signature returned"); + return CHIP_ERROR_INTERNAL; + } } if (signature.length > out_signature.Capacity()) { - CHIP_LOG_ERROR("ECDSA sign msg failure: unexpected signature size %tu vs %tu ", signature.length, out_signature.Capacity()); + CHIP_LOG_ERROR("ECDSA sign msg failure: unexpected signature size %llu vs %llu", static_cast(signature.length), + static_cast(out_signature.Capacity())); return CHIP_ERROR_NO_MEMORY; } out_signature.SetLength(signature.length); - std::memcpy(out_signature, signature.bytes, signature.length); + std::memcpy(out_signature.Bytes(), signature.bytes, signature.length); return CHIP_NO_ERROR; } @@ -98,20 +126,8 @@ if (!HasKeypair()) { return CHIP_ERROR_INCORRECT_STATE; } - NSData * hashData = [NSData dataWithBytes:hash length:hash_length]; - NSData * signature = [mKeypair ECDSA_sign_hash:hashData]; - if (!signature) { - CHIP_LOG_ERROR("ECDSA sign hash failure: no signature returned"); - return CHIP_ERROR_INTERNAL; - } - if (signature.length > out_signature.Capacity()) { - CHIP_LOG_ERROR( - "ECDSA sign hash failure: unexpected signature size %tu vs %tu ", signature.length, out_signature.Capacity()); - return CHIP_ERROR_NO_MEMORY; - } - out_signature.SetLength(signature.length); - std::memcpy(out_signature, signature.bytes, signature.length); - return CHIP_NO_ERROR; + + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } CHIP_ERROR CHIPP256KeypairBridge::ECDH_derive_secret( diff --git a/src/darwin/Framework/CHIPTests/CHIPTestKeys.m b/src/darwin/Framework/CHIPTests/CHIPTestKeys.m index 7a98d1252f6043..37a4e6f2d9912c 100644 --- a/src/darwin/Framework/CHIPTests/CHIPTestKeys.m +++ b/src/darwin/Framework/CHIPTests/CHIPTestKeys.m @@ -65,11 +65,11 @@ - (instancetype)init return self; } -- (NSData *)ECDSA_sign_hash:(NSData *)hash +- (NSData *)ECDSA_sign_message_DER:(NSData *)message { CFErrorRef error = NULL; CFDataRef outData - = SecKeyCreateSignature(_privateKey, kSecKeyAlgorithmECDSASignatureRFC4754, (__bridge CFDataRef) hash, &error); + = SecKeyCreateSignature(_privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef) message, &error); if (error != noErr) { NSLog(@"Failed to sign cert: %@", (__bridge NSError *) error);