Skip to content

Commit

Permalink
Make Darwin CHIPKeypair usable in a few more cases. (#18458)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Jul 20, 2023
1 parent 3babcd0 commit 406bd00
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

@interface CHIPToolKeypair : NSObject <CHIPKeypair>
- (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;
Expand Down
4 changes: 2 additions & 2 deletions examples/chip-tool-darwin/commands/common/CHIPToolKeypair.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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()];
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <r,s> 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);
Expand Down
4 changes: 2 additions & 2 deletions src/darwin/CHIPTool/CHIPTool/Framework Helpers/FabricKeys.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
35 changes: 27 additions & 8 deletions src/darwin/Framework/CHIP/CHIPKeypair.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,37 @@ NS_ASSUME_NONNULL_BEGIN

@protocol CHIPKeypair <NSObject>
@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 <r,s> 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 <r,s>
* 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

Expand Down
64 changes: 40 additions & 24 deletions src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/

#import "CHIPP256KeypairBridge.h"
#import "NSDataSpanConversion.h"

#import <CommonCrypto/CommonDigest.h>
#import <Security/SecKey.h>
#include <string>

Expand All @@ -28,6 +28,12 @@

CHIP_ERROR CHIPP256KeypairBridge::Init(id<CHIPKeypair> 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();
}
Expand Down Expand Up @@ -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<uint64_t>(signature.length),
static_cast<uint64_t>(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;
}

Expand All @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions src/darwin/Framework/CHIPTests/CHIPTestKeys.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 406bd00

Please sign in to comment.