diff --git a/examples/tv-app/android/java/JNIDACProvider.cpp b/examples/tv-app/android/java/JNIDACProvider.cpp index 19fb4dd64da1c1..2c4da223a5dbd3 100644 --- a/examples/tv-app/android/java/JNIDACProvider.cpp +++ b/examples/tv-app/android/java/JNIDACProvider.cpp @@ -69,30 +69,51 @@ JNIDACProvider::JNIDACProvider(jobject provider) env->ExceptionClear(); } - mGetDeviceAttestationCertPrivateKeyMethod = env->GetMethodID(JNIDACProviderClass, "GetDeviceAttestationCertPrivateKey", "()[B"); - if (mGetDeviceAttestationCertPrivateKeyMethod == nullptr) + mSignWithDeviceAttestationKeyMethod = env->GetMethodID(JNIDACProviderClass, "SignWithDeviceAttestationKey", "([B)[B"); + if (mSignWithDeviceAttestationKeyMethod == nullptr) { - ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetDeviceAttestationCertPrivateKey' method"); + ChipLogError(Zcl, "Failed to access JNIDACProvider 'SignWithDeviceAttestationKey' method"); env->ExceptionClear(); } +} - mGetDeviceAttestationCertPublicKeyKeyMethod = - env->GetMethodID(JNIDACProviderClass, "GetDeviceAttestationCertPublicKeyKey", "()[B"); - if (mGetDeviceAttestationCertPublicKeyKeyMethod == nullptr) +CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, MutableByteSpan & out_buffer) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnLogError(mJNIDACProviderObject != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(method != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); + + jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIDACProviderObject, method); + if (env->ExceptionCheck()) { - ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetDeviceAttestationCertPublicKeyKey' method"); + ChipLogError(Zcl, "Java exception in get Method"); + env->ExceptionDescribe(); env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; } + + if (outArray == nullptr || env->GetArrayLength(outArray) <= 0) + { + out_buffer.reduce_size(0); + return CHIP_NO_ERROR; + } + + JniByteArray JniOutArray(env, outArray); + return CopySpanToMutableSpan(JniOutArray.byteSpan(), out_buffer); } -CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, MutableByteSpan & out_buffer) +CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, const ByteSpan & in_buffer, MutableByteSpan & out_buffer) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnLogError(mJNIDACProviderObject != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnLogError(method != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); - jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIDACProviderObject, method); + jbyteArray in_buffer_jbyteArray = env->NewByteArray((jsize)(in_buffer.size())); + env->SetByteArrayRegion(in_buffer_jbyteArray, 0, (int) in_buffer.size(), reinterpret_cast(in_buffer.data())); + + jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIDACProviderObject, method, in_buffer_jbyteArray); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in get Method"); @@ -101,6 +122,8 @@ CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, MutableByteSpan return CHIP_ERROR_INCORRECT_STATE; } + env->DeleteLocalRef(in_buffer_jbyteArray); + if (outArray == nullptr || env->GetArrayLength(outArray) <= 0) { out_buffer.reduce_size(0); @@ -135,38 +158,20 @@ CHIP_ERROR JNIDACProvider::GetProductAttestationIntermediateCert(MutableByteSpan return GetJavaByteByMethod(mGetProductAttestationIntermediateCertMethod, out_pai_buffer); } -// TODO: This should be moved to a method of P256Keypair -CHIP_ERROR LoadKeypairFromRaw(ByteSpan private_key, ByteSpan public_key, Crypto::P256Keypair & keypair) -{ - Crypto::P256SerializedKeypair serialized_keypair; - ReturnErrorOnFailure(serialized_keypair.SetLength(private_key.size() + public_key.size())); - memcpy(serialized_keypair.Bytes(), public_key.data(), public_key.size()); - memcpy(serialized_keypair.Bytes() + public_key.size(), private_key.data(), private_key.size()); - return keypair.Deserialize(serialized_keypair); -} - CHIP_ERROR JNIDACProvider::SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, MutableByteSpan & out_signature_buffer) { ChipLogProgress(Zcl, "Received SignWithDeviceAttestationKey"); - Crypto::P256ECDSASignature signature; - Crypto::P256Keypair keypair; + uint8_t mAsn1SignatureBytes[73]; - VerifyOrReturnError(IsSpanUsable(out_signature_buffer), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(IsSpanUsable(message_to_sign), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_signature_buffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + MutableByteSpan asn1_signature_buffer(mAsn1SignatureBytes, sizeof(mAsn1SignatureBytes)); - uint8_t privateKeyBuf[Crypto::kP256_PrivateKey_Length]; - MutableByteSpan privateKeyBufSpan(privateKeyBuf); - ReturnErrorOnFailure(GetJavaByteByMethod(mGetDeviceAttestationCertPrivateKeyMethod, privateKeyBufSpan)); - - uint8_t publicKeyBuf[Crypto::kP256_PublicKey_Length]; - MutableByteSpan publicKeyBufSpan(publicKeyBuf); - ReturnErrorOnFailure(GetJavaByteByMethod(mGetDeviceAttestationCertPublicKeyKeyMethod, publicKeyBufSpan)); - - // In a non-exemplary implementation, the public key is not needed here. It is used here merely because - // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present. - ReturnErrorOnFailure(LoadKeypairFromRaw(privateKeyBufSpan, publicKeyBufSpan, keypair)); - ReturnErrorOnFailure(keypair.ECDSA_sign_msg(message_to_sign.data(), message_to_sign.size(), signature)); + CHIP_ERROR error = GetJavaByteByMethod(mSignWithDeviceAttestationKeyMethod, message_to_sign, asn1_signature_buffer); + if (error != CHIP_NO_ERROR) + { + ChipLogProgress(Zcl, "SignWithDeviceAttestationKey failed"); + return error; + } - return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, out_signature_buffer); + return chip::Crypto::EcdsaAsn1SignatureToRaw(32, ByteSpan(asn1_signature_buffer.data(), asn1_signature_buffer.size()), + out_signature_buffer); } diff --git a/examples/tv-app/android/java/JNIDACProvider.h b/examples/tv-app/android/java/JNIDACProvider.h index 1498eb66c07dcd..9c419367253c5f 100644 --- a/examples/tv-app/android/java/JNIDACProvider.h +++ b/examples/tv-app/android/java/JNIDACProvider.h @@ -33,11 +33,11 @@ class JNIDACProvider : public chip::Credentials::DeviceAttestationCredentialsPro private: CHIP_ERROR GetJavaByteByMethod(jmethodID method, chip::MutableByteSpan & out_buffer); + CHIP_ERROR GetJavaByteByMethod(jmethodID method, const chip::ByteSpan & in_buffer, chip::MutableByteSpan & out_buffer); jobject mJNIDACProviderObject = nullptr; jmethodID mGetCertificationDeclarationMethod = nullptr; jmethodID mGetFirmwareInformationMethod = nullptr; jmethodID mGetDeviceAttestationCertMethod = nullptr; jmethodID mGetProductAttestationIntermediateCertMethod = nullptr; - jmethodID mGetDeviceAttestationCertPrivateKeyMethod = nullptr; - jmethodID mGetDeviceAttestationCertPublicKeyKeyMethod = nullptr; + jmethodID mSignWithDeviceAttestationKeyMethod = nullptr; }; diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProvider.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProvider.java index 7b2e0786717dd1..1fc81b1cd7abc3 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProvider.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProvider.java @@ -26,7 +26,14 @@ public interface DACProvider { byte[] GetProductAttestationIntermediateCert(); - byte[] GetDeviceAttestationCertPrivateKey(); - - byte[] GetDeviceAttestationCertPublicKeyKey(); + /** + * Sign a mesage with the device attestation key. + * + *

The signature should be a SHA256withECDSA Signature that's returned in the ECDSA X9.62 Asn1 + * format. This is the default behavior when using java.security.Signature with an EC P-256 curve. + * + * @param message The message to sign + * @return The signature in ECDSA X9.62 Asn1 format. + */ + byte[] SignWithDeviceAttestationKey(byte[] message); } diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProviderStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProviderStub.java index 2aead7ad66aaab..80b8b8a99c3a0a 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProviderStub.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/DACProviderStub.java @@ -1,6 +1,14 @@ package com.matter.tv.server.tvapp; import android.util.Base64; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPrivateKeySpec; public class DACProviderStub implements DACProvider { @@ -46,12 +54,29 @@ public byte[] GetProductAttestationIntermediateCert() { } @Override - public byte[] GetDeviceAttestationCertPrivateKey() { - return Base64.decode(kDevelopmentDAC_PrivateKey_FFF1_8001, Base64.DEFAULT); - } + public byte[] SignWithDeviceAttestationKey(byte[] message) { - @Override - public byte[] GetDeviceAttestationCertPublicKeyKey() { - return Base64.decode(kDevelopmentDAC_PublicKey_FFF1_8001, Base64.DEFAULT); + try { + byte[] privateKeyBytes = Base64.decode(kDevelopmentDAC_PrivateKey_FFF1_8001, Base64.DEFAULT); + + AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("EC"); + algorithmParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algorithmParameters.getParameterSpec(ECParameterSpec.class); + ECPrivateKeySpec ecPrivateKeySpec = + new ECPrivateKeySpec(new BigInteger(1, privateKeyBytes), parameterSpec); + + KeyFactory keyFactory = KeyFactory.getInstance("EC"); + PrivateKey privateKey = keyFactory.generatePrivate(ecPrivateKeySpec); + + Signature signature = Signature.getInstance("SHA256withECDSA"); + signature.initSign(privateKey); + + signature.update(message); + + return signature.sign(); + + } catch (Exception e) { + return null; + } } } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/DACProviderStub.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/DACProviderStub.java index fe70069db1bda2..9dbae27c6e5982 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/DACProviderStub.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/DACProviderStub.java @@ -2,6 +2,14 @@ import android.util.Base64; import com.chip.casting.DACProvider; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPrivateKeySpec; public class DACProviderStub implements DACProvider { @@ -47,12 +55,29 @@ public byte[] GetProductAttestationIntermediateCert() { } @Override - public byte[] GetDeviceAttestationCertPrivateKey() { - return Base64.decode(kDevelopmentDAC_PrivateKey_FFF1_8001, Base64.DEFAULT); - } + public byte[] SignWithDeviceAttestationKey(byte[] message) { - @Override - public byte[] GetDeviceAttestationCertPublicKeyKey() { - return Base64.decode(kDevelopmentDAC_PublicKey_FFF1_8001, Base64.DEFAULT); + try { + byte[] privateKeyBytes = Base64.decode(kDevelopmentDAC_PrivateKey_FFF1_8001, Base64.DEFAULT); + + AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("EC"); + algorithmParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algorithmParameters.getParameterSpec(ECParameterSpec.class); + ECPrivateKeySpec ecPrivateKeySpec = + new ECPrivateKeySpec(new BigInteger(1, privateKeyBytes), parameterSpec); + + KeyFactory keyFactory = KeyFactory.getInstance("EC"); + PrivateKey privateKey = keyFactory.generatePrivate(ecPrivateKeySpec); + + Signature signature = Signature.getInstance("SHA256withECDSA"); + signature.initSign(privateKey); + + signature.update(message); + + return signature.sign(); + + } catch (Exception e) { + return null; + } } } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/DACProvider.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/DACProvider.java index 64dd43be96c4ab..c49d73ab98c86e 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/DACProvider.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/DACProvider.java @@ -26,7 +26,14 @@ public interface DACProvider { byte[] GetProductAttestationIntermediateCert(); - byte[] GetDeviceAttestationCertPrivateKey(); - - byte[] GetDeviceAttestationCertPublicKeyKey(); + /** + * Sign a mesage with the device attestation key. + * + *

The signature should be a SHA256withECDSA Signature that's returned in the ECDSA X9.62 Asn1 + * format. This is the default behavior when using java.security.Signature with an EC P-256 curve. + * + * @param message The message to sign + * @return The signature in ECDSA X9.62 Asn1 format. + */ + byte[] SignWithDeviceAttestationKey(byte[] message); } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.cpp index 19fb4dd64da1c1..2c4da223a5dbd3 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.cpp @@ -69,30 +69,51 @@ JNIDACProvider::JNIDACProvider(jobject provider) env->ExceptionClear(); } - mGetDeviceAttestationCertPrivateKeyMethod = env->GetMethodID(JNIDACProviderClass, "GetDeviceAttestationCertPrivateKey", "()[B"); - if (mGetDeviceAttestationCertPrivateKeyMethod == nullptr) + mSignWithDeviceAttestationKeyMethod = env->GetMethodID(JNIDACProviderClass, "SignWithDeviceAttestationKey", "([B)[B"); + if (mSignWithDeviceAttestationKeyMethod == nullptr) { - ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetDeviceAttestationCertPrivateKey' method"); + ChipLogError(Zcl, "Failed to access JNIDACProvider 'SignWithDeviceAttestationKey' method"); env->ExceptionClear(); } +} - mGetDeviceAttestationCertPublicKeyKeyMethod = - env->GetMethodID(JNIDACProviderClass, "GetDeviceAttestationCertPublicKeyKey", "()[B"); - if (mGetDeviceAttestationCertPublicKeyKeyMethod == nullptr) +CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, MutableByteSpan & out_buffer) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnLogError(mJNIDACProviderObject != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(method != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); + + jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIDACProviderObject, method); + if (env->ExceptionCheck()) { - ChipLogError(Zcl, "Failed to access JNIDACProvider 'GetDeviceAttestationCertPublicKeyKey' method"); + ChipLogError(Zcl, "Java exception in get Method"); + env->ExceptionDescribe(); env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; } + + if (outArray == nullptr || env->GetArrayLength(outArray) <= 0) + { + out_buffer.reduce_size(0); + return CHIP_NO_ERROR; + } + + JniByteArray JniOutArray(env, outArray); + return CopySpanToMutableSpan(JniOutArray.byteSpan(), out_buffer); } -CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, MutableByteSpan & out_buffer) +CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, const ByteSpan & in_buffer, MutableByteSpan & out_buffer) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnLogError(mJNIDACProviderObject != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnLogError(method != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); - jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIDACProviderObject, method); + jbyteArray in_buffer_jbyteArray = env->NewByteArray((jsize)(in_buffer.size())); + env->SetByteArrayRegion(in_buffer_jbyteArray, 0, (int) in_buffer.size(), reinterpret_cast(in_buffer.data())); + + jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIDACProviderObject, method, in_buffer_jbyteArray); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in get Method"); @@ -101,6 +122,8 @@ CHIP_ERROR JNIDACProvider::GetJavaByteByMethod(jmethodID method, MutableByteSpan return CHIP_ERROR_INCORRECT_STATE; } + env->DeleteLocalRef(in_buffer_jbyteArray); + if (outArray == nullptr || env->GetArrayLength(outArray) <= 0) { out_buffer.reduce_size(0); @@ -135,38 +158,20 @@ CHIP_ERROR JNIDACProvider::GetProductAttestationIntermediateCert(MutableByteSpan return GetJavaByteByMethod(mGetProductAttestationIntermediateCertMethod, out_pai_buffer); } -// TODO: This should be moved to a method of P256Keypair -CHIP_ERROR LoadKeypairFromRaw(ByteSpan private_key, ByteSpan public_key, Crypto::P256Keypair & keypair) -{ - Crypto::P256SerializedKeypair serialized_keypair; - ReturnErrorOnFailure(serialized_keypair.SetLength(private_key.size() + public_key.size())); - memcpy(serialized_keypair.Bytes(), public_key.data(), public_key.size()); - memcpy(serialized_keypair.Bytes() + public_key.size(), private_key.data(), private_key.size()); - return keypair.Deserialize(serialized_keypair); -} - CHIP_ERROR JNIDACProvider::SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, MutableByteSpan & out_signature_buffer) { ChipLogProgress(Zcl, "Received SignWithDeviceAttestationKey"); - Crypto::P256ECDSASignature signature; - Crypto::P256Keypair keypair; + uint8_t mAsn1SignatureBytes[73]; - VerifyOrReturnError(IsSpanUsable(out_signature_buffer), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(IsSpanUsable(message_to_sign), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_signature_buffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + MutableByteSpan asn1_signature_buffer(mAsn1SignatureBytes, sizeof(mAsn1SignatureBytes)); - uint8_t privateKeyBuf[Crypto::kP256_PrivateKey_Length]; - MutableByteSpan privateKeyBufSpan(privateKeyBuf); - ReturnErrorOnFailure(GetJavaByteByMethod(mGetDeviceAttestationCertPrivateKeyMethod, privateKeyBufSpan)); - - uint8_t publicKeyBuf[Crypto::kP256_PublicKey_Length]; - MutableByteSpan publicKeyBufSpan(publicKeyBuf); - ReturnErrorOnFailure(GetJavaByteByMethod(mGetDeviceAttestationCertPublicKeyKeyMethod, publicKeyBufSpan)); - - // In a non-exemplary implementation, the public key is not needed here. It is used here merely because - // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present. - ReturnErrorOnFailure(LoadKeypairFromRaw(privateKeyBufSpan, publicKeyBufSpan, keypair)); - ReturnErrorOnFailure(keypair.ECDSA_sign_msg(message_to_sign.data(), message_to_sign.size(), signature)); + CHIP_ERROR error = GetJavaByteByMethod(mSignWithDeviceAttestationKeyMethod, message_to_sign, asn1_signature_buffer); + if (error != CHIP_NO_ERROR) + { + ChipLogProgress(Zcl, "SignWithDeviceAttestationKey failed"); + return error; + } - return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, out_signature_buffer); + return chip::Crypto::EcdsaAsn1SignatureToRaw(32, ByteSpan(asn1_signature_buffer.data(), asn1_signature_buffer.size()), + out_signature_buffer); } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.h index 1498eb66c07dcd..9c419367253c5f 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/JNIDACProvider.h @@ -33,11 +33,11 @@ class JNIDACProvider : public chip::Credentials::DeviceAttestationCredentialsPro private: CHIP_ERROR GetJavaByteByMethod(jmethodID method, chip::MutableByteSpan & out_buffer); + CHIP_ERROR GetJavaByteByMethod(jmethodID method, const chip::ByteSpan & in_buffer, chip::MutableByteSpan & out_buffer); jobject mJNIDACProviderObject = nullptr; jmethodID mGetCertificationDeclarationMethod = nullptr; jmethodID mGetFirmwareInformationMethod = nullptr; jmethodID mGetDeviceAttestationCertMethod = nullptr; jmethodID mGetProductAttestationIntermediateCertMethod = nullptr; - jmethodID mGetDeviceAttestationCertPrivateKeyMethod = nullptr; - jmethodID mGetDeviceAttestationCertPublicKeyKeyMethod = nullptr; + jmethodID mSignWithDeviceAttestationKeyMethod = nullptr; }; diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm index 69c94d12c4e3ef..bac90428ce2417 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm @@ -260,19 +260,9 @@ - (void)setDacHolder:(DeviceAttestationCredentialsHolder * _Nonnull)deviceAttest const_cast(static_cast(productAttestationIntermediateCertNsData.bytes)), productAttestationIntermediateCertNsData.length); - NSData * deviceAttestationCertPrivateKeyNsData = deviceAttestationCredentials.getDeviceAttestationCertPrivateKey; - chip::MutableByteSpan deviceAttestationCertPrivateKey = chip::MutableByteSpan( - const_cast(static_cast(deviceAttestationCertPrivateKeyNsData.bytes)), - deviceAttestationCertPrivateKeyNsData.length); - - NSData * deviceAttestationCertPublicKeyKeyNsData = deviceAttestationCredentials.getDeviceAttestationCertPublicKey; - chip::MutableByteSpan deviceAttestationCertPublicKeyKey = chip::MutableByteSpan( - const_cast(static_cast(deviceAttestationCertPublicKeyKeyNsData.bytes)), - deviceAttestationCertPublicKeyKeyNsData.length); - self->_deviceAttestationCredentialsProvider = new DeviceAttestationCredentialsProviderImpl(&certificationDeclaration, &firmwareInformation, &deviceAttestationCert, - &productAttestationIntermediateCert, &deviceAttestationCertPrivateKey, &deviceAttestationCertPublicKeyKey); + &productAttestationIntermediateCert, deviceAttestationCredentials.getDeviceAttestationCertPrivateKeyRef); SetDeviceAttestationCredentialsProvider(self->_deviceAttestationCredentialsProvider); diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.h index b5926f2c68c697..44d4dee2169c43 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.h +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.h @@ -16,6 +16,7 @@ */ #import +#import #ifndef DeviceAttestationCredentialsHolder_h #define DeviceAttestationCredentialsHolder_h @@ -27,8 +28,7 @@ firmwareInformation:(NSData * _Nonnull)firmwareInformation deviceAttestationCert:(NSData * _Nonnull)deviceAttestationCert productAttestationIntermediateCert:(NSData * _Nonnull)productAttestationIntermediateCert - deviceAttestationCertPrivateKey:(NSData * _Nonnull)deviceAttestationCertPrivateKey - deviceAttestationCertPublicKeyKey:(NSData * _Nonnull)deviceAttestationCertPublicKeyKey; + deviceAttestationCertPrivateKeyRef:(SecKeyRef _Nonnull)deviceAttestationCertPrivateKeyRef; - (NSData * _Nonnull)getCertificationDeclaration; @@ -38,9 +38,7 @@ - (NSData * _Nonnull)getProductAttestationIntermediateCert; -- (NSData * _Nonnull)getDeviceAttestationCertPrivateKey; - -- (NSData * _Nonnull)getDeviceAttestationCertPublicKey; +- (SecKeyRef _Nonnull)getDeviceAttestationCertPrivateKeyRef; @end diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.m b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.m index 7c41b9b1630288..1f10ec47f7f185 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.m +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.m @@ -29,21 +29,18 @@ @interface DeviceAttestationCredentialsHolder () @property NSData * productAttestationIntermediateCert; -@property NSData * deviceAttestationCertPrivateKey; - -@property NSData * deviceAttestationCertPublicKey; +@property SecKeyRef deviceAttestationCertPrivateKeyRef; @end @implementation DeviceAttestationCredentialsHolder -- (DeviceAttestationCredentialsHolder * _Nonnull)initWithCertificationDeclaration:(NSData * _Nonnull)certificationDeclaration - firmwareInformation:(NSData * _Nonnull)firmwareInformation - deviceAttestationCert:(NSData * _Nonnull)deviceAttestationCert - productAttestationIntermediateCert: - (NSData * _Nonnull)productAttestationIntermediateCert - deviceAttestationCertPrivateKey:(NSData * _Nonnull)deviceAttestationCertPrivateKey - deviceAttestationCertPublicKeyKey:(NSData * _Nonnull)deviceAttestationCertPublicKey +- (DeviceAttestationCredentialsHolder * _Nonnull) + initWithCertificationDeclaration:(NSData * _Nonnull)certificationDeclaration + firmwareInformation:(NSData * _Nonnull)firmwareInformation + deviceAttestationCert:(NSData * _Nonnull)deviceAttestationCert + productAttestationIntermediateCert:(NSData * _Nonnull)productAttestationIntermediateCert + deviceAttestationCertPrivateKeyRef:(SecKeyRef _Nonnull)deviceAttestationCertPrivateKeyRef { self = [super init]; if (self) { @@ -51,8 +48,7 @@ - (DeviceAttestationCredentialsHolder * _Nonnull)initWithCertificationDeclaratio _firmwareInformation = firmwareInformation; _deviceAttestationCert = deviceAttestationCert; _productAttestationIntermediateCert = productAttestationIntermediateCert; - _deviceAttestationCertPrivateKey = deviceAttestationCertPrivateKey; - _deviceAttestationCertPublicKey = deviceAttestationCertPublicKey; + _deviceAttestationCertPrivateKeyRef = deviceAttestationCertPrivateKeyRef; } return self; } @@ -62,28 +58,24 @@ - (NSData * _Nonnull)getCertificationDeclaration return _certificationDeclaration; } -- (NSData * _Nonnull)getFirmwareInformation; +- (NSData * _Nonnull)getFirmwareInformation { return _firmwareInformation; } -- (NSData * _Nonnull)getDeviceAttestationCert; +- (NSData * _Nonnull)getDeviceAttestationCert { return _deviceAttestationCert; } -- (NSData * _Nonnull)getProductAttestationIntermediateCert; +- (NSData * _Nonnull)getProductAttestationIntermediateCert { return _productAttestationIntermediateCert; } -- (NSData * _Nonnull)getDeviceAttestationCertPrivateKey; +- (SecKeyRef)getDeviceAttestationCertPrivateKeyRef { - return _deviceAttestationCertPrivateKey; + return _deviceAttestationCertPrivateKeyRef; } -- (NSData * _Nonnull)getDeviceAttestationCertPublicKey; -{ - return _deviceAttestationCertPublicKey; -} @end diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.hpp b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.hpp index ba3558f400560a..21d63ba88d2d05 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.hpp +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.hpp @@ -21,6 +21,8 @@ #include #include +#include + class DeviceAttestationCredentialsProviderImpl : public chip::Credentials::DeviceAttestationCredentialsProvider { public: @@ -28,8 +30,7 @@ class DeviceAttestationCredentialsProviderImpl : public chip::Credentials::Devic chip::MutableByteSpan * firmwareInformation, chip::MutableByteSpan * deviceAttestationCert, chip::MutableByteSpan * productAttestationIntermediateCert, - chip::MutableByteSpan * deviceAttestationCertPrivateKey, - chip::MutableByteSpan * deviceAttestationCertPublicKeyKey); + SecKeyRef deviceAttestationCertPrivateKeyRef); CHIP_ERROR GetCertificationDeclaration(chip::MutableByteSpan & outCertificationDeclaration) override; CHIP_ERROR GetFirmwareInformation(chip::MutableByteSpan & outFirmwareInformation) override; @@ -43,15 +44,5 @@ class DeviceAttestationCredentialsProviderImpl : public chip::Credentials::Devic chip::MutableByteSpan mFirmwareInformation; chip::MutableByteSpan mDeviceAttestationCert; chip::MutableByteSpan mProductAttestationIntermediateCert; - chip::MutableByteSpan mDeviceAttestationCertPrivateKey; - chip::MutableByteSpan mDeviceAttestationCertPublicKeyKey; - - CHIP_ERROR LoadKeypairFromRaw(chip::ByteSpan privateKey, chip::ByteSpan publicKey, chip::Crypto::P256Keypair & keypair) - { - chip::Crypto::P256SerializedKeypair serialized_keypair; - ReturnErrorOnFailure(serialized_keypair.SetLength(privateKey.size() + publicKey.size())); - memcpy(serialized_keypair.Bytes(), publicKey.data(), publicKey.size()); - memcpy(serialized_keypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size()); - return keypair.Deserialize(serialized_keypair); - } + SecKeyRef mDeviceAttestationCertPrivateKeyRef; }; diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.mm index 59a0a70f88e0f5..7008ffba969e72 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.mm @@ -18,11 +18,11 @@ #include "DeviceAttestationCredentialsProviderImpl.hpp" #import +#import DeviceAttestationCredentialsProviderImpl::DeviceAttestationCredentialsProviderImpl(chip::MutableByteSpan * certificationDeclaration, chip::MutableByteSpan * firmwareInformation, chip::MutableByteSpan * deviceAttestationCert, - chip::MutableByteSpan * productAttestationIntermediateCert, chip::MutableByteSpan * deviceAttestationCertPrivateKey, - chip::MutableByteSpan * deviceAttestationCertPublicKeyKey) + chip::MutableByteSpan * productAttestationIntermediateCert, SecKeyRef deviceAttestationCertPrivateKeyRef) { if (certificationDeclaration != nullptr) { mCertificationDeclaration @@ -47,19 +47,7 @@ productAttestationIntermediateCert->size()); } - if (deviceAttestationCertPrivateKey != nullptr) { - mDeviceAttestationCertPrivateKey - = chip::MutableByteSpan(new uint8_t[deviceAttestationCertPrivateKey->size()], deviceAttestationCertPrivateKey->size()); - memcpy(mDeviceAttestationCertPrivateKey.data(), deviceAttestationCertPrivateKey->data(), - deviceAttestationCertPrivateKey->size()); - } - - if (deviceAttestationCertPublicKeyKey != nullptr) { - mDeviceAttestationCertPublicKeyKey = chip::MutableByteSpan( - new uint8_t[deviceAttestationCertPublicKeyKey->size()], deviceAttestationCertPublicKeyKey->size()); - memcpy(mDeviceAttestationCertPublicKeyKey.data(), deviceAttestationCertPublicKeyKey->data(), - deviceAttestationCertPublicKeyKey->size()); - } + mDeviceAttestationCertPrivateKeyRef = deviceAttestationCertPrivateKeyRef; } CHIP_ERROR DeviceAttestationCredentialsProviderImpl::GetCertificationDeclaration( @@ -121,17 +109,56 @@ const chip::ByteSpan & messageToSign, chip::MutableByteSpan & outSignatureBuffer) { ChipLogProgress(AppServer, "DeviceAttestationCredentialsProviderImpl::SignWithDeviceAttestationKey called"); - chip::Crypto::P256ECDSASignature signature; - chip::Crypto::P256Keypair keypair; - VerifyOrReturnError(IsSpanUsable(outSignatureBuffer), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(IsSpanUsable(messageToSign), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(outSignatureBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + CHIP_ERROR result = CHIP_NO_ERROR; + CFDataRef dataToSign = nil; + CFDataRef asn1SignatureData = nil; + uint8_t mAsn1SignatureBytes[256]; + chip::MutableByteSpan asn1SignatureByteSpan = chip::MutableByteSpan(mAsn1SignatureBytes, sizeof(mAsn1SignatureBytes)); + CFErrorRef error = nil; + size_t signatureLen = 0; + + do { + dataToSign = CFDataCreate(CFAllocatorGetDefault(), messageToSign.data(), messageToSign.size()); + if (nil == dataToSign) { + ChipLogError( + AppServer, "DeviceAttestationCredentialsProviderImpl::SignWithDeviceAttestationKey failed to create buffer"); + result = CHIP_ERROR_NO_MEMORY; + break; + } + + asn1SignatureData = SecKeyCreateSignature( + mDeviceAttestationCertPrivateKeyRef, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, dataToSign, &error); + if (nil != error || nil == asn1SignatureData) { + ChipLogError(AppServer, + "DeviceAttestationCredentialsProviderImpl::SignWithDeviceAttestationKey failed to sign the message. error = %lu", + CFErrorGetCode(error)); + result = CHIP_ERROR_INVALID_ARGUMENT; + break; + } + + signatureLen = CFDataGetLength(asn1SignatureData); - // In a non-exemplary implementation, the public key is not needed here. It is used here merely because - // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present. - ReturnErrorOnFailure(LoadKeypairFromRaw(mDeviceAttestationCertPrivateKey, mDeviceAttestationCertPublicKeyKey, keypair)); - ReturnErrorOnFailure(keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature)); + CFDataGetBytes(asn1SignatureData, CFRangeMake(0, signatureLen), asn1SignatureByteSpan.data()); + asn1SignatureByteSpan.reduce_size(signatureLen); + + CHIP_ERROR conversionError = chip::Crypto::EcdsaAsn1SignatureToRaw( + 32, chip::ByteSpan(asn1SignatureByteSpan.data(), asn1SignatureByteSpan.size()), outSignatureBuffer); + if (CHIP_NO_ERROR != conversionError) { + ChipLogError(AppServer, + "DeviceAttestationCredentialsProviderImpl::SignWithDeviceAttestationKey failed to convert to raw signature."); + result = conversionError; + break; + } + } while (0); + + if (dataToSign != nil) { + CFRelease(dataToSign); + } + + if (asn1SignatureData != nil) { + CFRelease(asn1SignatureData); + } - return CopySpanToMutableSpan(chip::ByteSpan { signature.ConstBytes(), signature.Length() }, outSignatureBuffer); + return result; } diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ExampleDAC.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ExampleDAC.swift index c34386792fdf63..d05423b711292c 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ExampleDAC.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ExampleDAC.swift @@ -42,12 +42,19 @@ class ExampleDAC : DeviceAttestationCredentialsHolder { override func getProductAttestationIntermediateCert() -> Data { return KPAI_FFF1_8000_Cert_Array } - - override func getDeviceAttestationCertPrivateKey() -> Data { - return kDevelopmentDAC_PrivateKey_FFF1_8001 - } - - override func getDeviceAttestationCertPublicKey() -> Data { - return kDevelopmentDAC_PublicKey_FFF1_8001 + + override func getDeviceAttestationCertPrivateKeyRef() -> Unmanaged { + var privateKey = Data() + privateKey.append(kDevelopmentDAC_PublicKey_FFF1_8001); + privateKey.append(kDevelopmentDAC_PrivateKey_FFF1_8001); + + let privateKeyRef: SecKey = SecKeyCreateWithData(privateKey as NSData, + [ + kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, + kSecAttrKeyClass: kSecAttrKeyClassPrivate, + kSecAttrKeySizeInBits: 256 + ] as NSDictionary, nil)! + + return Unmanaged.passRetained(privateKeyRef); } }