Skip to content

Commit f504993

Browse files
Merge pull request #613 from NordicSemiconductor/bugfix/errata-16350
Patches Errata 16350
2 parents 982d641 + c5e040d commit f504993

5 files changed

Lines changed: 13 additions & 43 deletions

File tree

mesh/src/main/java/no/nordicsemi/android/mesh/MeshProvisioningHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ private boolean parseProvisioneeConfirmation(final byte[] data) {
499499
}
500500

501501
private void sendRandomConfirmationPDU(final UnprovisionedMeshNode node) {
502-
final ProvisioningRandomConfirmationState provisioningRandomConfirmation = new ProvisioningRandomConfirmationState(node, this, mInternalTransportCallbacks, mStatusCallbacks);
502+
final ProvisioningRandomConfirmationState provisioningRandomConfirmation = new ProvisioningRandomConfirmationState(node, mInternalTransportCallbacks, mStatusCallbacks);
503503
provisioningState = provisioningRandomConfirmation;
504504
provisioningRandomConfirmation.executeSend();
505505
}

mesh/src/main/java/no/nordicsemi/android/mesh/provisionerstates/ProvisioningConfirmationState.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import no.nordicsemi.android.mesh.logger.MeshLogger;
2626

2727
import java.nio.ByteBuffer;
28+
import java.util.Arrays;
2829

2930
import androidx.annotation.NonNull;
3031
import androidx.annotation.Nullable;
@@ -83,7 +84,6 @@ public State getState() {
8384

8485
@Override
8586
public void executeSend() {
86-
8787
final byte[] provisioningConfirmationPDU = createProvisioningConfirmation();
8888
mStatusCallbacks.onProvisioningStateChanged(mNode, States.PROVISIONING_CONFIRMATION_SENT, provisioningConfirmationPDU);
8989
mInternalTransportCallbacks.sendProvisioningPdu(mNode, provisioningConfirmationPDU);
@@ -93,7 +93,9 @@ public void executeSend() {
9393
public boolean parseData(@NonNull final byte[] data) {
9494
mStatusCallbacks.onProvisioningStateChanged(mNode, States.PROVISIONING_CONFIRMATION_RECEIVED, data);
9595
parseProvisioneeConfirmation(data);
96-
return true;
96+
// Errata E16350 added an extra validation whether the received Confirmation is different
97+
// than Provisioner's one.
98+
return !Arrays.equals(mNode.provisioningConfirmation, mNode.provisioneeConfirmation);
9799
}
98100

99101
private byte[] createProvisioningConfirmation() {
@@ -129,6 +131,7 @@ private byte[] createProvisioningConfirmation() {
129131
final byte[] confirmationData = buffer.array();
130132

131133
final byte[] confirmationValue = SecureUtils.calculateCMAC(confirmationData, confirmationKey);
134+
mNode.provisioningConfirmation = confirmationValue;
132135

133136
buffer = ByteBuffer.allocate(confirmationValue.length + 2);
134137
buffer.put(new byte[]{MeshManagerApi.PDU_TYPE_PROVISIONING, TYPE_PROVISIONING_CONFIRMATION});

mesh/src/main/java/no/nordicsemi/android/mesh/provisionerstates/ProvisioningPublicKeyState.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.security.NoSuchProviderException;
4444
import java.security.PrivateKey;
4545
import java.security.spec.InvalidKeySpecException;
46+
import java.util.Arrays;
4647

4748
import javax.crypto.KeyAgreement;
4849

@@ -98,7 +99,9 @@ public boolean parseData(@NonNull final byte[] data) {
9899
provisioningStatusCallbacks.onProvisioningStateChanged(node, States.PROVISIONING_PUBLIC_KEY_RECEIVED, data);
99100
}
100101
generateSharedECDHSecret(data);
101-
return true;
102+
// Errata E16350 added an extra validation whether the received Public Key
103+
// is different than Provisioner's one.
104+
return !Arrays.equals(node.provisionerPublicKeyXY, node.provisioneePublicKeyXY);
102105
}
103106

104107
private void generateKeyPairs() {

mesh/src/main/java/no/nordicsemi/android/mesh/provisionerstates/ProvisioningRandomConfirmationState.java

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,21 @@
2323
package no.nordicsemi.android.mesh.provisionerstates;
2424

2525
import java.nio.ByteBuffer;
26-
import java.util.Arrays;
2726

2827
import androidx.annotation.NonNull;
2928
import androidx.annotation.RestrictTo;
30-
import no.nordicsemi.android.mesh.InternalProvisioningCallbacks;
29+
3130
import no.nordicsemi.android.mesh.InternalTransportCallbacks;
3231
import no.nordicsemi.android.mesh.MeshManagerApi;
3332
import no.nordicsemi.android.mesh.MeshProvisioningStatusCallbacks;
3433
import no.nordicsemi.android.mesh.logger.MeshLogger;
3534
import no.nordicsemi.android.mesh.utils.MeshParserUtils;
36-
import no.nordicsemi.android.mesh.utils.SecureUtils;
3735

3836
public class ProvisioningRandomConfirmationState extends ProvisioningState {
3937

4038
private final String TAG = ProvisioningRandomConfirmationState.class.getSimpleName();
4139
private final UnprovisionedMeshNode node;
4240
private final MeshProvisioningStatusCallbacks mStatusCallbacks;
43-
private final InternalProvisioningCallbacks provisioningCallbacks;
4441
private final InternalTransportCallbacks mInternalTransportCallbacks;
4542

4643
/**
@@ -49,16 +46,13 @@ public class ProvisioningRandomConfirmationState extends ProvisioningState {
4946
* @param node {@link UnprovisionedMeshNode} node.
5047
* @param internalTransportCallbacks {@link InternalTransportCallbacks} callbacks.
5148
* @param provisioningStatusCallbacks {@link MeshProvisioningStatusCallbacks} callbacks.
52-
* @param internalProvisioningCallbacks {@link InternalProvisioningCallbacks} callbacks.
5349
*/
5450
@RestrictTo(RestrictTo.Scope.LIBRARY)
5551
public ProvisioningRandomConfirmationState(@NonNull final UnprovisionedMeshNode node,
56-
@NonNull final InternalProvisioningCallbacks internalProvisioningCallbacks,
5752
@NonNull final InternalTransportCallbacks internalTransportCallbacks,
5853
@NonNull final MeshProvisioningStatusCallbacks provisioningStatusCallbacks) {
5954
super();
6055
this.node = node;
61-
this.provisioningCallbacks = internalProvisioningCallbacks;
6256
this.mInternalTransportCallbacks = internalTransportCallbacks;
6357
this.mStatusCallbacks = provisioningStatusCallbacks;
6458
}
@@ -79,7 +73,7 @@ public void executeSend() {
7973
public boolean parseData(@NonNull final byte[] data) {
8074
mStatusCallbacks.onProvisioningStateChanged(node, States.PROVISIONING_RANDOM_RECEIVED, data);
8175
parseProvisioneeRandom(data);
82-
return provisioneeMatches();
76+
return true;
8377
}
8478

8579
private byte[] createProvisionerRandomPDU() {
@@ -92,37 +86,6 @@ private byte[] createProvisionerRandomPDU() {
9286
return data;
9387
}
9488

95-
private boolean provisioneeMatches() {
96-
final byte[] provisioneeRandom = node.getProvisioneeRandom();
97-
98-
final byte[] confirmationInputs = provisioningCallbacks.generateConfirmationInputs(node.getProvisionerPublicKeyXY(),
99-
node.getProvisioneePublicKeyXY());
100-
MeshLogger.verbose(TAG, "Confirmation inputs: " + MeshParserUtils.bytesToHex(confirmationInputs, false));
101-
102-
//Generate a confirmation salt of the confirmation inputs
103-
final byte[] confirmationSalt = SecureUtils.calculateSalt(confirmationInputs);
104-
MeshLogger.verbose(TAG, "Confirmation salt: " + MeshParserUtils.bytesToHex(confirmationSalt, false));
105-
106-
final byte[] ecdhSecret = node.getSharedECDHSecret();
107-
108-
//Generate the confirmationKey by calculating the K1 of ECDH, confirmationSalt and ASCII value of "prck".
109-
final byte[] confirmationKey = SecureUtils.calculateK1(ecdhSecret, confirmationSalt, SecureUtils.PRCK);
110-
MeshLogger.verbose(TAG, "Confirmation key: " + MeshParserUtils.bytesToHex(confirmationKey, false));
111-
112-
//Generate authentication value from the user input pin
113-
final byte[] authenticationValue = node.getAuthenticationValue();
114-
MeshLogger.verbose(TAG, "Authentication value: " + MeshParserUtils.bytesToHex(authenticationValue, false));
115-
116-
ByteBuffer buffer = ByteBuffer.allocate(provisioneeRandom.length + authenticationValue.length);
117-
buffer.put(provisioneeRandom);
118-
buffer.put(authenticationValue);
119-
final byte[] confirmationData = buffer.array();
120-
121-
final byte[] confirmationValue = SecureUtils.calculateCMAC(confirmationData, confirmationKey);
122-
123-
return Arrays.equals(confirmationValue, node.getProvisioneeConfirmation());
124-
}
125-
12689
private void parseProvisioneeRandom(final byte[] provisioneeRandomPDU) {
12790
final ByteBuffer buffer = ByteBuffer.allocate(provisioneeRandomPDU.length - 2);
12891
buffer.put(provisioneeRandomPDU, 2, buffer.limit());

mesh/src/main/java/no/nordicsemi/android/mesh/provisionerstates/UnprovisionedBaseMeshNode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ abstract class UnprovisionedBaseMeshNode implements Parcelable {
4848
byte[] sharedECDHSecret;
4949
byte[] provisionerRandom;
5050
byte[] provisioneeConfirmation;
51+
byte[] provisioningConfirmation;
5152
byte[] authenticationValue;
5253
byte[] provisioneeRandom;
5354
protected byte[] networkKey;

0 commit comments

Comments
 (0)