| /* | |
| * | |
| * Copyright (c) 2017 Nest Labs, Inc. | |
| * All rights reserved. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| /** | |
| * @file | |
| * OpenSSL implementations of elliptic curve functions used by Weave security code. | |
| * | |
| */ | |
| #ifndef OPENSSL_EXPERIMENTAL_ECJPAKE | |
| #define OPENSSL_EXPERIMENTAL_ECJPAKE | |
| #endif | |
| #include "WeaveCrypto.h" | |
| #include "EllipticCurve.h" | |
| #include <Weave/Core/WeaveEncoding.h> | |
| #include <Weave/Support/CodeUtils.h> | |
| #if WEAVE_WITH_OPENSSL | |
| #include <string.h> | |
| #include <openssl/obj_mac.h> | |
| #if WEAVE_CONFIG_ALLOW_NON_STANDARD_ELLIPTIC_CURVES | |
| #include <openssl/objects.h> | |
| #endif | |
| #if WEAVE_IS_ECJPAKE_ENABLED | |
| #include <openssl/ecjpake.h> | |
| #endif | |
| namespace nl { | |
| namespace Weave { | |
| namespace Crypto { | |
| using namespace nl::Weave::ASN1; | |
| using namespace nl::Weave::Encoding; | |
| // ============================================================ | |
| // OpenSSL implementations of primary elliptic curve functions | |
| // used by Weave security code. | |
| // ============================================================ | |
| #if WEAVE_CONFIG_USE_OPENSSL_ECC | |
| // Generate an ECDSA signature given a message hash and a EC private key. | |
| NL_DLL_EXPORT WEAVE_ERROR GenerateECDSASignature(OID curveOID, | |
| const uint8_t *msgHash, uint8_t msgHashLen, | |
| const EncodedECPrivateKey& encodedPrivKey, | |
| EncodedECDSASignature& encodedSig) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| EC_KEY *key = NULL; | |
| ECDSA_SIG *ecSig = NULL; | |
| // Decode the private key into a EC_KEY object. | |
| err = DecodeECKey(curveOID, &encodedPrivKey, NULL, key); | |
| SuccessOrExit(err); | |
| // Generate the signature for the given message hash. | |
| ecSig = ECDSA_do_sign(msgHash, msgHashLen, key); | |
| VerifyOrExit(ecSig != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: use better error | |
| // Encode the signature into the output structure. | |
| err = EncodeECDSASignature(ecSig, encodedSig); | |
| SuccessOrExit(err); | |
| exit: | |
| ECDSA_SIG_free(ecSig); | |
| EC_KEY_free(key); | |
| return err; | |
| } | |
| // Generate an ECDSA signature given a message hash and a EC private key. | |
| WEAVE_ERROR GenerateECDSASignature(OID curveOID, | |
| const uint8_t *msgHash, uint8_t msgHashLen, | |
| const EncodedECPrivateKey& encodedPrivKey, | |
| uint8_t *fixedLenSig) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| EC_KEY *key = NULL; | |
| ECDSA_SIG *ecSig = NULL; | |
| // Decode the private key into a EC_KEY object. | |
| err = DecodeECKey(curveOID, &encodedPrivKey, NULL, key); | |
| SuccessOrExit(err); | |
| // Generate the signature for the given message hash. | |
| ecSig = ECDSA_do_sign(msgHash, msgHashLen, key); | |
| VerifyOrExit(ecSig != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: use better error | |
| // Encode the signature into the output structure. | |
| err = ECDSASigToFixedLenSig(curveOID, ecSig, fixedLenSig); | |
| SuccessOrExit(err); | |
| exit: | |
| ECDSA_SIG_free(ecSig); | |
| EC_KEY_free(key); | |
| return err; | |
| } | |
| // Verify an ECDSA signature. | |
| NL_DLL_EXPORT WEAVE_ERROR VerifyECDSASignature(OID curveOID, | |
| const uint8_t *msgHash, uint8_t msgHashLen, | |
| const EncodedECDSASignature& encodedSig, | |
| const EncodedECPublicKey& encodedPubKey) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| EC_KEY *pubKey = NULL; | |
| ECDSA_SIG *sig = NULL; | |
| int res; | |
| // Decode the public key into a EC_KEY object. | |
| err = DecodeECKey(curveOID, NULL, &encodedPubKey, pubKey); | |
| SuccessOrExit(err); | |
| err = DecodeECDSASignature(encodedSig, sig); | |
| SuccessOrExit(err); | |
| res = ECDSA_do_verify(msgHash, msgHashLen, sig, pubKey); | |
| VerifyOrExit(res == 1, err = WEAVE_ERROR_INVALID_SIGNATURE); | |
| exit: | |
| ECDSA_SIG_free(sig); | |
| EC_KEY_free(pubKey); | |
| return err; | |
| } | |
| // Verify an ECDSA signature. | |
| WEAVE_ERROR VerifyECDSASignature(OID curveOID, | |
| const uint8_t *msgHash, uint8_t msgHashLen, | |
| const uint8_t *fixedLenSig, | |
| const EncodedECPublicKey& encodedPubKey) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| EC_KEY *pubKey = NULL; | |
| ECDSA_SIG *sig = NULL; | |
| int res; | |
| // Decode the public key into a EC_KEY object. | |
| err = DecodeECKey(curveOID, NULL, &encodedPubKey, pubKey); | |
| SuccessOrExit(err); | |
| // Convert fixed-length signature into a ECDSA_SIG object. | |
| err = FixedLenSigToECDSASig(curveOID, fixedLenSig, sig); | |
| SuccessOrExit(err); | |
| // Verify the signature for the given message hash. | |
| res = ECDSA_do_verify(msgHash, msgHashLen, sig, pubKey); | |
| VerifyOrExit(res == 1, err = WEAVE_ERROR_INVALID_SIGNATURE); | |
| exit: | |
| ECDSA_SIG_free(sig); | |
| EC_KEY_free(pubKey); | |
| return err; | |
| } | |
| // Generate a public/private key pair suitable for Elliptic Curve Diffie-Hellman. | |
| WEAVE_ERROR GenerateECDHKey(OID curveOID, EncodedECPublicKey& encodedPubKey, EncodedECPrivateKey& encodedPrivKey) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| EC_GROUP *ecGroup = NULL; | |
| EC_KEY *key = NULL; | |
| const BIGNUM *privKey; | |
| int res, privKeyLen; | |
| err = GetECGroupForCurve(curveOID, ecGroup); | |
| SuccessOrExit(err); | |
| key = EC_KEY_new(); | |
| VerifyOrExit(key != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| res = EC_KEY_set_group(key, ecGroup); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| res = EC_KEY_generate_key(key); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); // TODO: map OpenSSL error | |
| err = EncodeX962ECPoint(curveOID, ecGroup, EC_KEY_get0_public_key(key), encodedPubKey.ECPoint, encodedPubKey.ECPointLen, encodedPubKey.ECPointLen); | |
| SuccessOrExit(err); | |
| privKey = EC_KEY_get0_private_key(key); | |
| privKeyLen = BN_num_bytes(privKey); | |
| VerifyOrExit(encodedPrivKey.PrivKeyLen >= privKeyLen, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| BN_bn2bin(privKey, encodedPrivKey.PrivKey); | |
| encodedPrivKey.PrivKeyLen = privKeyLen; | |
| exit: | |
| EC_GROUP_free(ecGroup); | |
| EC_KEY_free(key); | |
| return err; | |
| } | |
| WEAVE_ERROR ECDHComputeSharedSecret(OID curveOID, const EncodedECPublicKey& encodedPubKey, const EncodedECPrivateKey& encodedPrivKey, | |
| uint8_t *sharedSecretBuf, uint16_t sharedSecretBufSize, uint16_t& sharedSecretLen) | |
| { | |
| WEAVE_ERROR err; | |
| EC_GROUP *ecGroup = NULL; | |
| EC_POINT *pubKey = NULL; | |
| BIGNUM *privKey = NULL; | |
| err = GetECGroupForCurve(curveOID, ecGroup); | |
| SuccessOrExit(err); | |
| err = DecodeX962ECPoint(encodedPubKey.ECPoint, encodedPubKey.ECPointLen, ecGroup, pubKey); | |
| SuccessOrExit(err); | |
| privKey = BN_bin2bn(encodedPrivKey.PrivKey, encodedPrivKey.PrivKeyLen, NULL); | |
| VerifyOrExit(privKey != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| err = ECDHComputeSharedSecret(curveOID, ecGroup, pubKey, privKey, sharedSecretBuf, sharedSecretBufSize, sharedSecretLen); | |
| SuccessOrExit(err); | |
| exit: | |
| BN_clear_free(privKey); | |
| EC_POINT_free(pubKey); | |
| EC_GROUP_free(ecGroup); | |
| return err; | |
| } | |
| int GetCurveSize(const OID curveOID) | |
| { | |
| int curveSize = 0; | |
| EC_GROUP *ecGroup = NULL; | |
| if (GetECGroupForCurve(curveOID, ecGroup) == WEAVE_NO_ERROR) | |
| curveSize = GetCurveSize(curveOID, ecGroup); | |
| EC_GROUP_free(ecGroup); | |
| return curveSize; | |
| } | |
| WEAVE_ERROR GetCurveG(OID curveOID, EncodedECPublicKey& encodedG) | |
| { | |
| WEAVE_ERROR err; | |
| EC_GROUP *ecGroup = NULL; | |
| err = GetECGroupForCurve(curveOID, ecGroup); | |
| SuccessOrExit(err); | |
| err = EncodeX962ECPoint(curveOID, ecGroup, EC_GROUP_get0_generator(ecGroup), encodedG.ECPoint, encodedG.ECPointLen, encodedG.ECPointLen); | |
| SuccessOrExit(err); | |
| exit: | |
| EC_GROUP_free(ecGroup); | |
| return err; | |
| } | |
| #endif // WEAVE_CONFIG_USE_OPENSSL_ECC | |
| // ============================================================ | |
| // OpenSSL-specific elliptic curve utility functions. | |
| // ============================================================ | |
| // ECDSA_SIG_get0() and ECDSA_SIG_set0() methods were introduced in OpenSSL | |
| // version 1.1.0; for older versions of OpenSSL these methods are defined here. | |
| #if (OPENSSL_VERSION_NUMBER < 0x10100000L) | |
| static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) | |
| { | |
| if (pr != NULL) | |
| *pr = sig->r; | |
| if (ps != NULL) | |
| *ps = sig->s; | |
| } | |
| static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) | |
| { | |
| if (r == NULL || s == NULL) | |
| return 0; | |
| BN_clear_free(sig->r); | |
| BN_clear_free(sig->s); | |
| sig->r = r; | |
| sig->s = s; | |
| return 1; | |
| } | |
| #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) | |
| int GetCurveSize(const OID curveOID, const EC_GROUP *ecGroup) | |
| { | |
| return ((EC_GROUP_get_degree(ecGroup) + 7) / 8); | |
| } | |
| NL_DLL_EXPORT WEAVE_ERROR GetECGroupForCurve(OID curveOID, EC_GROUP *& ecGroup) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| int curveNID; | |
| switch (curveOID) | |
| { | |
| case kOID_EllipticCurve_secp160r1: | |
| curveNID = NID_secp160r1; | |
| break; | |
| case kOID_EllipticCurve_prime192v1: | |
| curveNID = NID_X9_62_prime192v1; | |
| break; | |
| case kOID_EllipticCurve_secp224r1: | |
| curveNID = NID_secp224r1; | |
| break; | |
| case kOID_EllipticCurve_prime256v1: | |
| curveNID = NID_X9_62_prime256v1; | |
| break; | |
| default: | |
| #if WEAVE_CONFIG_ALLOW_NON_STANDARD_ELLIPTIC_CURVES | |
| { | |
| ASN1_OBJECT *curveASN1Obj; | |
| const uint8_t *encodedOID; | |
| uint16_t encodedOIDLen; | |
| if (!GetEncodedObjectID(curveOID, encodedOID, encodedOIDLen)) | |
| ExitNow(err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| curveASN1Obj = c2i_ASN1_OBJECT(&curveASN1Obj, &encodedOID, encodedOIDLen); | |
| VerifyOrExit(curveASN1Obj != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| curveNID = OBJ_obj2nid(curveASN1Obj); | |
| ASN1_OBJECT_free(curveASN1Obj) | |
| VerifyOrExit(curveNID != NID_undef, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| } | |
| #endif | |
| case kOID_Unknown: | |
| ExitNow(err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| break; | |
| } | |
| ecGroup = EC_GROUP_new_by_curve_name(curveNID); | |
| VerifyOrExit(ecGroup != NULL, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| // Only include the curve name when generating an ASN.1 encoding of a public key. | |
| EC_GROUP_set_asn1_flag(ecGroup, OPENSSL_EC_NAMED_CURVE); | |
| exit: | |
| return err; | |
| } | |
| // Perform the Elliptic Curve Diffie-Hellman computation to generate a shared secret | |
| // from a EC public key and a private key. | |
| NL_DLL_EXPORT WEAVE_ERROR ECDHComputeSharedSecret(OID curveOID, const EC_GROUP *ecGroup, | |
| const EC_POINT *pubKeyPoint, const BIGNUM *privKeyBN, | |
| uint8_t *sharedSecretBuf, uint16_t sharedSecretBufSize, uint16_t& sharedSecretLen) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| EC_POINT *sharedSecretPoint = NULL; | |
| BIGNUM *sharedSecretX = NULL; | |
| BIGNUM *sharedSecretY = NULL; | |
| int sharedSecretXLen; | |
| // Determine the output size of the shared key in bytes. This is equal to the size | |
| // of the curve prime. | |
| sharedSecretLen = GetCurveSize(curveOID, ecGroup); | |
| VerifyOrExit(sharedSecretLen != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| VerifyOrExit(sharedSecretLen <= sharedSecretBufSize, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| // Create a EC_POINT object to hold the shared key point. | |
| sharedSecretPoint = EC_POINT_new(ecGroup); | |
| VerifyOrExit(sharedSecretPoint != NULL, err = WEAVE_ERROR_NO_MEMORY); // TODO: translate OpenSSL error | |
| // Multiply the public key point by the private key number to produce the shared key point. | |
| // (This is the crux of the EC Diffie-Hellman algorithm). | |
| if (!EC_POINT_mul(ecGroup, sharedSecretPoint, NULL, pubKeyPoint, privKeyBN, NULL)) | |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: translate OpenSSL error | |
| // Extract the coordinate values from the shared key point. | |
| sharedSecretX = BN_new(); | |
| VerifyOrExit(sharedSecretX != NULL, err = WEAVE_ERROR_NO_MEMORY); // TODO: translate OpenSSL error | |
| sharedSecretY = BN_new(); | |
| VerifyOrExit(sharedSecretX != NULL, err = WEAVE_ERROR_NO_MEMORY); // TODO: translate OpenSSL error | |
| if (!EC_POINT_get_affine_coordinates_GFp(ecGroup, sharedSecretPoint, sharedSecretX, sharedSecretY, NULL)) | |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: translate OpenSSL error | |
| // Determine the size in bytes of the shared key X coordinate. | |
| sharedSecretXLen = BN_num_bytes(sharedSecretX); | |
| VerifyOrExit(sharedSecretXLen <= (int)sharedSecretLen, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| // Convert the shared key X coordinate to a big-endian byte array, padded on the left with 0s | |
| // to the shared key output size. | |
| memset(sharedSecretBuf, 0, sharedSecretLen); | |
| if (sharedSecretXLen != (int)BN_bn2bin(sharedSecretX, sharedSecretBuf + sharedSecretLen - sharedSecretXLen)) | |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: translate OpenSSL error | |
| exit: | |
| BN_clear_free(sharedSecretX); | |
| BN_clear_free(sharedSecretY); | |
| EC_POINT_clear_free(sharedSecretPoint); | |
| return err; | |
| } | |
| NL_DLL_EXPORT WEAVE_ERROR EncodeX962ECPoint(OID curveOID, EC_GROUP *ecGroup, const EC_POINT *point, uint8_t *buf, uint16_t bufSize, uint16_t& encodedPointLen) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| BIGNUM *x = NULL; | |
| BIGNUM *y = NULL; | |
| int fieldLen, valLen; | |
| // Encoding point at infinity not supported. | |
| VerifyOrExit(!EC_POINT_is_at_infinity(ecGroup, point), err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| // Determine the encoded size of the point's fields. This is equal to the size of the curve prime. | |
| fieldLen = GetCurveSize(curveOID, ecGroup); | |
| VerifyOrExit(fieldLen != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| // Verify that the buffer is big enough. | |
| encodedPointLen = 1 + (fieldLen * 2); | |
| VerifyOrExit(bufSize >= encodedPointLen, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| // Get the point's coordinates. | |
| x = BN_new(); | |
| VerifyOrExit(x != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| y = BN_new(); | |
| VerifyOrExit(y != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| if (!EC_POINT_get_affine_coordinates_GFp(ecGroup, point, x, y, NULL)) | |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: translate OpenSSL error | |
| // Clear the output buffer. This primes it with zeros in case one of the coordinates | |
| // is less than fieldLen long, in which case the zeros act as padding. | |
| memset(buf, 0, encodedPointLen); | |
| // Encode the format byte (0x04 = uncompressed point). | |
| buf[0] = kX963EncodedPointFormat_Uncompressed; | |
| // Encode the X value right aligned in the field length. | |
| valLen = BN_num_bytes(x); | |
| VerifyOrExit(valLen <= fieldLen, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| BN_bn2bin(x, &buf[1 + fieldLen - valLen]); | |
| // Encode the Y value, also right aligned. | |
| valLen = BN_num_bytes(y); | |
| VerifyOrExit(valLen <= fieldLen, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| BN_bn2bin(y, &buf[1 + fieldLen + fieldLen - valLen]); | |
| exit: | |
| BN_free(x); | |
| BN_free(y); | |
| return err; | |
| } | |
| NL_DLL_EXPORT WEAVE_ERROR DecodeX962ECPoint(const uint8_t *encodedPoint, uint16_t encodedPointLen, EC_GROUP *group, EC_POINT *& point) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| BIGNUM *x = NULL; | |
| BIGNUM *y = NULL; | |
| point = NULL; | |
| err = DecodeX962ECPoint(encodedPoint, encodedPointLen, x, y); | |
| SuccessOrExit(err); | |
| point = EC_POINT_new(group); | |
| VerifyOrExit(point != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: translate OpenSSL error | |
| // TODO: validate point is on curve | |
| if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, NULL)) | |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); // TODO: translate OpenSSL error | |
| exit: | |
| if (err != WEAVE_NO_ERROR && point != NULL) | |
| { | |
| EC_POINT_free(point); | |
| point = NULL; | |
| } | |
| BN_free(x); | |
| BN_free(y); | |
| return err; | |
| } | |
| WEAVE_ERROR DecodeX962ECPoint(const uint8_t *encodedPoint, uint16_t encodedPointLen, BIGNUM *& x, BIGNUM *& y) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| uint16_t fieldSize; | |
| x = y = NULL; | |
| VerifyOrExit(encodedPointLen >= 3, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| // Verify that the encoding is an uncompressed point (0x04). Point-at-infinity (0x00) and compressed | |
| // points (0x02, 0x03) are not supported. | |
| VerifyOrExit(*encodedPoint == kX963EncodedPointFormat_Uncompressed, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| // Length must be odd (encoding byte plus x and y coordinates, each the same size). | |
| VerifyOrExit((encodedPointLen & 1) == 1, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| fieldSize = (encodedPointLen - 1) / 2; | |
| x = BN_bin2bn(encodedPoint + 1, fieldSize, NULL); | |
| VerifyOrExit(x != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| y = BN_bin2bn(encodedPoint + 1 + fieldSize, fieldSize, NULL); | |
| VerifyOrExit(x != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| exit: | |
| if (err != WEAVE_NO_ERROR) | |
| { | |
| BN_free(x); | |
| x = NULL; | |
| BN_free(y); | |
| y = NULL; | |
| } | |
| return err; | |
| } | |
| // Decode an elliptic curve private key or/and public key in X9.62 format, and return an EC_KEY object. | |
| NL_DLL_EXPORT WEAVE_ERROR DecodeECKey(OID curveOID, const EncodedECPrivateKey *encodedPrivKey, const EncodedECPublicKey *encodedPubKey, EC_KEY *& ecKey) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| EC_GROUP *ecGroup = NULL; | |
| EC_POINT *pubKeyPoint = NULL; | |
| BIGNUM *privKeyBN = NULL; | |
| int res; | |
| ecKey = NULL; | |
| // Verify that at least one of the (public/private) key inputs is provided. | |
| VerifyOrExit(encodedPrivKey != NULL || encodedPubKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| // TODO: optimize this to eliminate duplication of the EC_POINT and EC_GROUP objects. | |
| err = GetECGroupForCurve(curveOID, ecGroup); | |
| SuccessOrExit(err); | |
| ecKey = EC_KEY_new(); | |
| VerifyOrExit(ecKey != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| res = EC_KEY_set_group(ecKey, ecGroup); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| if (encodedPubKey != NULL) | |
| { | |
| VerifyOrExit(encodedPubKey->ECPoint != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| err = DecodeX962ECPoint(encodedPubKey->ECPoint, encodedPubKey->ECPointLen, ecGroup, pubKeyPoint); | |
| SuccessOrExit(err); | |
| res = EC_KEY_set_public_key(ecKey, pubKeyPoint); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| } | |
| if (encodedPrivKey != NULL) | |
| { | |
| VerifyOrExit(encodedPrivKey->PrivKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| privKeyBN = BN_bin2bn(encodedPrivKey->PrivKey, encodedPrivKey->PrivKeyLen, NULL); | |
| VerifyOrExit(privKeyBN != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| res = EC_KEY_set_private_key(ecKey, privKeyBN); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| } | |
| exit: | |
| BN_free(privKeyBN); | |
| EC_POINT_free(pubKeyPoint); | |
| if (err != WEAVE_NO_ERROR) | |
| { | |
| EC_KEY_free(ecKey); | |
| ecKey = NULL; | |
| } | |
| EC_GROUP_free(ecGroup); | |
| return err; | |
| } | |
| // Encode an OpenSSL ECDSA signature into a pair of buffers. | |
| WEAVE_ERROR EncodeECDSASignature(const ECDSA_SIG *sig, EncodedECDSASignature& encodedSig) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| const BIGNUM *sigR; | |
| const BIGNUM *sigS; | |
| int valLen; | |
| ECDSA_SIG_get0(sig, &sigR, &sigS); | |
| valLen = BN_num_bytes(sigR); | |
| VerifyOrExit(valLen <= encodedSig.RLen, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| BN_bn2bin(sigR, encodedSig.R); | |
| if ((encodedSig.R[0] & 0x80) != 0) | |
| { | |
| VerifyOrExit(valLen < encodedSig.RLen, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| memmove(encodedSig.R + 1, encodedSig.R, valLen); | |
| encodedSig.R[0] = 0; | |
| encodedSig.RLen = valLen + 1; | |
| } | |
| else | |
| encodedSig.RLen = valLen; | |
| valLen = BN_num_bytes(sigS); | |
| VerifyOrExit(valLen <= encodedSig.SLen, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| BN_bn2bin(sigS, encodedSig.S); | |
| if ((encodedSig.S[0] & 0x80) != 0) | |
| { | |
| VerifyOrExit(valLen < encodedSig.SLen, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| memmove(encodedSig.S + 1, encodedSig.S, valLen); | |
| encodedSig.S[0] = 0; | |
| encodedSig.SLen = valLen + 1; | |
| } | |
| else | |
| encodedSig.SLen = valLen; | |
| exit: | |
| return err; | |
| } | |
| // Decode an ECDSA signature consisting of r and s values encoded as a big-endian sequences of bytes. | |
| WEAVE_ERROR DecodeECDSASignature(const EncodedECDSASignature& encodedSig, ECDSA_SIG *& sig) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| BIGNUM *sigR = NULL; | |
| BIGNUM *sigS = NULL; | |
| int retVal; | |
| sig = ECDSA_SIG_new(); | |
| VerifyOrExit(sig != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| sigR = BN_bin2bn(encodedSig.R, encodedSig.RLen, sigR); | |
| VerifyOrExit(sigR != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| sigS = BN_bin2bn(encodedSig.S, encodedSig.SLen, sigS); | |
| VerifyOrExit(sigS != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| retVal = ECDSA_SIG_set0(sig, sigR, sigS); | |
| VerifyOrExit(retVal != 0, err = WEAVE_ERROR_NO_MEMORY); | |
| exit: | |
| if (err != WEAVE_NO_ERROR && sig != NULL) | |
| { | |
| ECDSA_SIG_free(sig); | |
| sig = NULL; | |
| } | |
| return err; | |
| } | |
| // Convert an OpenSSL ECDSA signature into a fixed-length signature. | |
| WEAVE_ERROR ECDSASigToFixedLenSig(OID curveOID, const ECDSA_SIG *ecSig, uint8_t *fixedLenSig) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| const BIGNUM *sigR; | |
| const BIGNUM *sigS; | |
| uint16_t fieldLen; | |
| int valLen; | |
| fieldLen = GetCurveSize(curveOID); | |
| VerifyOrExit(fieldLen != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| ECDSA_SIG_get0(ecSig, &sigR, &sigS); | |
| // Clear the output buffer. This primes it with zeros in case one of the signature | |
| // companents {r, s} is less than fieldLen long, in which case the zeros act as padding. | |
| memset(fixedLenSig, 0, 2 * fieldLen); | |
| // Encode the R value right aligned in the field length. | |
| valLen = BN_num_bytes(sigR); | |
| VerifyOrExit(valLen <= fieldLen, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| BN_bn2bin(sigR, &fixedLenSig[fieldLen - valLen]); | |
| // Encode the S value, also right aligned. | |
| valLen = BN_num_bytes(sigS); | |
| VerifyOrExit(valLen <= fieldLen, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| BN_bn2bin(sigS, &fixedLenSig[2 * fieldLen - valLen]); | |
| exit: | |
| return err; | |
| } | |
| // Convert a fixed-length signature into an OpenSSL ECDSA signature format. | |
| extern WEAVE_ERROR FixedLenSigToECDSASig(OID curveOID, const uint8_t *fixedLenSig, ECDSA_SIG *& ecSig) | |
| { | |
| WEAVE_ERROR err = WEAVE_NO_ERROR; | |
| BIGNUM *sigR = NULL; | |
| BIGNUM *sigS = NULL; | |
| int retVal; | |
| uint16_t fieldLen; | |
| ecSig = ECDSA_SIG_new(); | |
| VerifyOrExit(ecSig != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| fieldLen = GetCurveSize(curveOID); | |
| VerifyOrExit(fieldLen != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| sigR = BN_bin2bn(fixedLenSig, fieldLen, sigR); | |
| VerifyOrExit(sigR != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| sigS = BN_bin2bn(fixedLenSig + fieldLen, fieldLen, sigS); | |
| VerifyOrExit(sigS != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| retVal = ECDSA_SIG_set0(ecSig, sigR, sigS); | |
| VerifyOrExit(retVal != 0, err = WEAVE_ERROR_NO_MEMORY); | |
| exit: | |
| if (err != WEAVE_NO_ERROR && ecSig != NULL) | |
| { | |
| ECDSA_SIG_free(ecSig); | |
| ecSig = NULL; | |
| } | |
| return err; | |
| } | |
| // ============================================================ | |
| // Elliptic Curve JPAKE Class Functions | |
| // ============================================================ | |
| #if WEAVE_IS_ECJPAKE_ENABLED && WEAVE_CONFIG_USE_OPENSSL_ECC | |
| static int GetCurveWordCount(const EC_GROUP *ecGroup) | |
| { | |
| int curveNID = EC_GROUP_get_curve_name(ecGroup); | |
| switch (curveNID) | |
| { | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP160R1 | |
| case NID_secp160r1: | |
| return 5; | |
| #endif | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP192R1 | |
| case NID_X9_62_prime192v1: | |
| return 6; | |
| #endif | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP224R1 | |
| case NID_secp224r1: | |
| return 7; | |
| #endif | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP256R1 | |
| case NID_X9_62_prime256v1: | |
| return 8; | |
| #endif | |
| default: | |
| #if WEAVE_CONFIG_ALLOW_NON_STANDARD_ELLIPTIC_CURVES | |
| return ((EC_GROUP_get_degree(ecGroup) + 31) / 32); | |
| #else | |
| return 0; | |
| #endif | |
| } | |
| } | |
| static int GetOrderWordCount(const EC_GROUP *ecGroup) | |
| { | |
| int curveNID = EC_GROUP_get_curve_name(ecGroup); | |
| switch (curveNID) | |
| { | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP160R1 | |
| case NID_secp160r1: | |
| return 6; | |
| #endif | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP192R1 | |
| case NID_X9_62_prime192v1: | |
| return 6; | |
| #endif | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP224R1 | |
| case NID_secp224r1: | |
| return 7; | |
| #endif | |
| #if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP256R1 | |
| case NID_X9_62_prime256v1: | |
| return 8; | |
| #endif | |
| default: | |
| #if WEAVE_CONFIG_ALLOW_NON_STANDARD_ELLIPTIC_CURVES | |
| BIGNUM *order = NULL; | |
| int ret = 0; | |
| if ((order = BN_new()) == NULL) goto err; | |
| if (!EC_GROUP_get_order(ecGroup, order, NULL)) goto err; | |
| ret = order->top; | |
| err: | |
| BN_free(order); | |
| return ret; | |
| #else | |
| return 0; | |
| #endif | |
| } | |
| } | |
| static WEAVE_ERROR EncodeECPointValue(const EC_GROUP *ecGroup, const EC_POINT *ecPoint, const uint8_t wordCount, uint8_t *& p) | |
| { | |
| WEAVE_ERROR err; | |
| BIGNUM *ecPointX = NULL; | |
| BIGNUM *ecPointY = NULL; | |
| ecPointX = BN_new(); | |
| VerifyOrExit(ecPointX != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| ecPointY = BN_new(); | |
| VerifyOrExit(ecPointY != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| if (!EC_POINT_get_affine_coordinates_GFp(ecGroup, ecPoint, ecPointX, ecPointY, NULL)) | |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| err = EncodeBIGNUMValueLE(*ecPointX, wordCount * sizeof(uint32_t), p); | |
| SuccessOrExit(err); | |
| err = EncodeBIGNUMValueLE(*ecPointY, wordCount * sizeof(uint32_t), p); | |
| SuccessOrExit(err); | |
| exit: | |
| BN_free(ecPointY); | |
| BN_free(ecPointX); | |
| return err; | |
| } | |
| static WEAVE_ERROR DecodeECPointValue(const EC_GROUP *ecGroup, EC_POINT *ecPoint, const uint8_t wordCount, const uint8_t *& p) | |
| { | |
| WEAVE_ERROR err; | |
| BIGNUM *ecPointX = NULL; | |
| BIGNUM *ecPointY = NULL; | |
| ecPointX = BN_new(); | |
| VerifyOrExit(ecPointX != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| ecPointY = BN_new(); | |
| VerifyOrExit(ecPointY != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| err = DecodeBIGNUMValueLE(*ecPointX, wordCount * sizeof(uint32_t), p); | |
| SuccessOrExit(err); | |
| err = DecodeBIGNUMValueLE(*ecPointY, wordCount * sizeof(uint32_t), p); | |
| SuccessOrExit(err); | |
| if (!EC_POINT_set_affine_coordinates_GFp(ecGroup, ecPoint, ecPointX, ecPointY, NULL)) | |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| exit: | |
| BN_free(ecPointY); | |
| BN_free(ecPointX); | |
| return err; | |
| } | |
| static WEAVE_ERROR EncodeStepPartFields(const ECJPAKE_CTX *ctx, const ECJPAKE_STEP_PART *stepPart, const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen) | |
| { | |
| WEAVE_ERROR err; | |
| uint8_t gWordCount, bWordCount; | |
| uint8_t *p = (uint8_t *)buf + stepDataLen; | |
| gWordCount = GetCurveWordCount(ECJPAKE_get_ecGroup(ctx)); | |
| VerifyOrExit(gWordCount != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| bWordCount = GetOrderWordCount(ECJPAKE_get_ecGroup(ctx)); | |
| VerifyOrExit(bWordCount != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| stepDataLen += (4 * gWordCount + bWordCount) * sizeof(uint32_t); | |
| VerifyOrExit(stepDataLen <= bufSize, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| err = EncodeECPointValue(ECJPAKE_get_ecGroup(ctx), stepPart->Gx, gWordCount, p); | |
| SuccessOrExit(err); | |
| err = EncodeECPointValue(ECJPAKE_get_ecGroup(ctx), stepPart->zkpx.Gr, gWordCount, p); | |
| SuccessOrExit(err); | |
| err = EncodeBIGNUMValueLE(*stepPart->zkpx.b, bWordCount * sizeof(uint32_t), p); | |
| SuccessOrExit(err); | |
| exit: | |
| return err; | |
| } | |
| static WEAVE_ERROR DecodeStepPartFields(const ECJPAKE_CTX *ctx, ECJPAKE_STEP_PART *stepPart, const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen) | |
| { | |
| WEAVE_ERROR err; | |
| uint8_t gWordCount, bWordCount; | |
| const uint8_t *p = buf + stepDataLen; | |
| gWordCount = GetCurveWordCount(ECJPAKE_get_ecGroup(ctx)); | |
| VerifyOrExit(gWordCount != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| bWordCount = GetOrderWordCount(ECJPAKE_get_ecGroup(ctx)); | |
| VerifyOrExit(bWordCount != 0, err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); | |
| stepDataLen += (4 * gWordCount + bWordCount) * sizeof(uint32_t); | |
| VerifyOrExit(stepDataLen <= bufSize, err = WEAVE_ERROR_BUFFER_TOO_SMALL); | |
| err = DecodeECPointValue(ECJPAKE_get_ecGroup(ctx), stepPart->Gx, gWordCount, p); | |
| SuccessOrExit(err); | |
| err = DecodeECPointValue(ECJPAKE_get_ecGroup(ctx), stepPart->zkpx.Gr, gWordCount, p); | |
| SuccessOrExit(err); | |
| err = DecodeBIGNUMValueLE(*stepPart->zkpx.b, bWordCount * sizeof(uint32_t), p); | |
| SuccessOrExit(err); | |
| exit: | |
| return err; | |
| } | |
| /* This function will be used by ECJPAKE to calculate SHA256 hash of Elliptic Curve Point */ | |
| static int ECJPAKE_HashECPoint(ECJPAKE_CTX *ctx, SHA256_CTX *sha, const EC_POINT *ecPoint) | |
| { | |
| WEAVE_ERROR err; | |
| uint8_t fieldWordCount; | |
| uint8_t *ecPointEncoded = NULL; | |
| uint8_t *p = NULL; | |
| int ret = 1; | |
| fieldWordCount = GetCurveWordCount(ECJPAKE_get_ecGroup(ctx)); | |
| VerifyOrExit(fieldWordCount != 0, ret = 0); | |
| ecPointEncoded = (uint8_t *)OPENSSL_malloc(2 * sizeof(uint32_t) * fieldWordCount); | |
| VerifyOrExit(ecPointEncoded != NULL, ret = 0); | |
| // Assign another pointer because the value is updated by EncodeECPointValue function | |
| p = ecPointEncoded; | |
| err = EncodeECPointValue(ECJPAKE_get_ecGroup(ctx), ecPoint, fieldWordCount, p); | |
| VerifyOrExit(err == WEAVE_NO_ERROR, ret = 0); | |
| SHA256_Update(sha, ecPointEncoded, 2 * sizeof(uint32_t) * fieldWordCount); | |
| exit: | |
| if (ecPointEncoded != NULL) OPENSSL_free(ecPointEncoded); | |
| return ret; | |
| } | |
| void EllipticCurveJPAKE::Init() | |
| { | |
| ECJPAKECtx = NULL; | |
| } | |
| /* clear secret content of JPAKE CTX Struct */ | |
| void EllipticCurveJPAKE::Shutdown() | |
| { | |
| Reset(); | |
| } | |
| /* clear secret content of JPAKE CTX Struct */ | |
| void EllipticCurveJPAKE::Reset() | |
| { | |
| if (ECJPAKECtx != NULL) | |
| { | |
| EC_GROUP *ecGroup = (EC_GROUP *)ECJPAKE_get_ecGroup(ECJPAKECtx); | |
| if (ecGroup != NULL) | |
| { | |
| EC_GROUP_free(ecGroup); | |
| } | |
| ECJPAKE_CTX_free(ECJPAKECtx); | |
| ECJPAKECtx = NULL; | |
| } | |
| } | |
| /* Init JPAKE CTX Struct */ | |
| WEAVE_ERROR EllipticCurveJPAKE::Init(const OID curveOID, const uint8_t *pw, const uint16_t pwLen, | |
| const uint8_t *localName, const uint16_t localNameLen, | |
| const uint8_t *peerName, const uint16_t peerNameLen) | |
| { | |
| WEAVE_ERROR err; | |
| EC_GROUP *ecGroup = NULL; | |
| BIGNUM *secret = NULL; | |
| // TODO: should we limit MAX length and check these inputs: pwLen, localNameLen, peerNameLen ? | |
| err = GetECGroupForCurve(curveOID, ecGroup); | |
| SuccessOrExit(err); | |
| secret = BN_new(); | |
| VerifyOrExit(secret != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| BN_bin2bn(pw, pwLen, secret); | |
| ECJPAKECtx = ECJPAKE_CTX_new(ecGroup, secret, localName, localNameLen, peerName, peerNameLen); | |
| VerifyOrExit(ECJPAKECtx != NULL, err = WEAVE_ERROR_NO_MEMORY); | |
| // Set ECJPAKE_HashECPoint function to be used by ECJPAKE for EC Point Hash | |
| ECJPAKE_Set_HashECPoint(ECJPAKE_HashECPoint); | |
| exit: | |
| BN_clear_free(secret); | |
| return err; | |
| } | |
| WEAVE_ERROR EllipticCurveJPAKE::GenerateStep1(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen) | |
| { | |
| WEAVE_ERROR err; | |
| ECJPAKE_STEP1 step1Data; | |
| int res; | |
| res = ECJPAKE_STEP1_init(&step1Data, ECJPAKECtx); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| res = ECJPAKE_STEP1_generate(&step1Data, ECJPAKECtx); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| err = EncodeStepPartFields(ECJPAKECtx, &step1Data.p1, buf, bufSize, stepDataLen); | |
| SuccessOrExit(err); | |
| err = EncodeStepPartFields(ECJPAKECtx, &step1Data.p2, buf, bufSize, stepDataLen); | |
| SuccessOrExit(err); | |
| exit: | |
| ECJPAKE_STEP1_release(&step1Data); | |
| return err; | |
| } | |
| WEAVE_ERROR EllipticCurveJPAKE::ProcessStep1(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen) | |
| { | |
| WEAVE_ERROR err; | |
| ECJPAKE_STEP1 step1Data; | |
| int res; | |
| res = ECJPAKE_STEP1_init(&step1Data, ECJPAKECtx); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| err = DecodeStepPartFields(ECJPAKECtx, &step1Data.p1, buf, bufSize, stepDataLen); | |
| SuccessOrExit(err); | |
| err = DecodeStepPartFields(ECJPAKECtx, &step1Data.p2, buf, bufSize, stepDataLen); | |
| SuccessOrExit(err); | |
| res = ECJPAKE_STEP1_process(ECJPAKECtx, &step1Data); | |
| VerifyOrExit(res, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| exit: | |
| ECJPAKE_STEP1_release(&step1Data); | |
| return err; | |
| } | |
| WEAVE_ERROR EllipticCurveJPAKE::GenerateStep2(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen) | |
| { | |
| WEAVE_ERROR err; | |
| ECJPAKE_STEP2 step2Data; | |
| int res; | |
| res = ECJPAKE_STEP2_init(&step2Data, ECJPAKECtx); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| res = ECJPAKE_STEP2_generate(&step2Data, ECJPAKECtx); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| err = EncodeStepPartFields(ECJPAKECtx, &step2Data, buf, bufSize, stepDataLen); | |
| SuccessOrExit(err); | |
| exit: | |
| ECJPAKE_STEP2_release(&step2Data); | |
| return err; | |
| } | |
| WEAVE_ERROR EllipticCurveJPAKE::ProcessStep2(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen) | |
| { | |
| WEAVE_ERROR err; | |
| ECJPAKE_STEP2 step2Data; | |
| int res; | |
| res = ECJPAKE_STEP2_init(&step2Data, ECJPAKECtx); | |
| VerifyOrExit(res, err = WEAVE_ERROR_NO_MEMORY); | |
| err = DecodeStepPartFields(ECJPAKECtx, &step2Data, buf, bufSize, stepDataLen); | |
| SuccessOrExit(err); | |
| res = ECJPAKE_STEP2_process(ECJPAKECtx, &step2Data); | |
| VerifyOrExit(res, err = WEAVE_ERROR_INVALID_ARGUMENT); | |
| exit: | |
| ECJPAKE_STEP2_release(&step2Data); | |
| return err; | |
| } | |
| uint8_t *EllipticCurveJPAKE::GetSharedSecret() | |
| { | |
| return (uint8_t *)ECJPAKE_get_shared_key(ECJPAKECtx); | |
| } | |
| int EllipticCurveJPAKE::GetCurveSize() | |
| { | |
| return (4 * GetCurveWordCount(ECJPAKE_get_ecGroup(ECJPAKECtx))); | |
| } | |
| #endif /* WEAVE_IS_ECJPAKE_ENABLED && WEAVE_CONFIG_USE_OPENSSL_ECC */ | |
| } // namespace Crypto | |
| } // namespace Weave | |
| } // namespace nl | |
| #endif /* WEAVE_WITH_OPENSSL */ |