blob: 50e67e1e82698a134de8f858eeda6af999515c93 [file] [log] [blame]
/*
*
* Copyright (c) 2013-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
* This file defines types, objects, and methods for working with
* Elliptic Curve (EC) Cryptography (ECC) Diffie-Hellman (DH) and
* digital signature algorithms (DSA) public key infrastructure,
* including keys and signatures.
*
*/
#ifndef ELLIPTICCURVE_H_
#define ELLIPTICCURVE_H_
#include "WeaveCrypto.h"
#include "HashAlgos.h"
#include <Weave/Support/ASN1.h>
#if WEAVE_CONFIG_USE_OPENSSL_ECC && !WEAVE_WITH_OPENSSL
#error "INVALID WEAVE CONFIG: OpenSSL ECC implementation enabled but OpenSSL not available (WEAVE_CONFIG_USE_OPENSSL_ECC == 1 && WEAVE_WITH_OPENSSL == 0)."
#endif
#if WEAVE_WITH_OPENSSL
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#endif
#define WEAVE_IS_ECJPAKE_ENABLED ( WEAVE_CONFIG_SUPPORT_PASE_CONFIG2 || \
WEAVE_CONFIG_SUPPORT_PASE_CONFIG3 || \
WEAVE_CONFIG_SUPPORT_PASE_CONFIG4 || \
WEAVE_CONFIG_SUPPORT_PASE_CONFIG5 )
#if WEAVE_CONFIG_USE_MICRO_ECC
#define uECC_WORD_SIZE 4
#define uECC_ENABLE_VLI_API 1
#include <micro-ecc/uECC.h>
#include <micro-ecc/uECC_vli.h>
#endif
#if WEAVE_CONFIG_USE_OPENSSL_ECC && WEAVE_IS_ECJPAKE_ENABLED
struct ECJPAKE_CTX;
#endif
namespace nl {
namespace Weave {
namespace Crypto {
using nl::Weave::ASN1::OID;
class EncodedECPublicKey
{
public:
uint8_t *ECPoint; // X9.62 format
uint16_t ECPointLen;
bool IsEqual(const EncodedECPublicKey& other) const;
};
class EncodedECDSASignature
{
public:
enum
{
kMaxValueLength = ((WEAVE_CONFIG_MAX_EC_BITS + 7) / 8) + 1
};
uint8_t *R; // ASN.1 DER Integer value format
uint8_t *S; // ASN.1 DER Integer value format
uint8_t RLen;
uint8_t SLen;
bool IsEqual(const EncodedECDSASignature& other) const;
};
class EncodedECPrivateKey
{
public:
uint8_t *PrivKey; // Integer in big-endian format
uint16_t PrivKeyLen;
bool IsEqual(const EncodedECPrivateKey& other) const;
};
#if WEAVE_CONFIG_USE_MICRO_ECC
enum
{
kuECC_WordSize = uECC_WORD_SIZE,
#if WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP256R1
kuECC_MaxWordCount = 8,
#elif WEAVE_CONFIG_SUPPORT_ELLIPTIC_CURVE_SECP224R1
kuECC_MaxWordCount = 7,
#else // SECP192R1 or SECP160R1
kuECC_MaxWordCount = 6,
#endif
kuECC_MaxByteCount = kuECC_MaxWordCount * kuECC_WordSize,
};
#endif // WEAVE_CONFIG_USE_MICRO_ECC
enum X963EncodedPointFormat
{
kX963EncodedPointFormat_PointAtInfinity = 0x00,
kX963EncodedPointFormat_Compressed_EvenY = 0x02,
kX963EncodedPointFormat_Compressed_OddY = 0x03,
kX963EncodedPointFormat_Uncompressed = 0x04,
kX963EncodedPointFormat_Hybrid_EvenY = 0x06,
kX963EncodedPointFormat_Hybrid_OddY = 0x07,
};
// =============================================================
// Primary elliptic curve functions used by Weave security code.
// =============================================================
/**
* Get Elliptic Curve size (in bytes).
*
* @param[in] curveOID Specified Elliptic Curve OID.
*
* @retval Returns 0 if specified curveOID is unsupported Elliptic Curve.
* Otherwise, returns curve size in bytes.
*
*/
extern int GetCurveSize(const OID curveOID);
extern WEAVE_ERROR GenerateECDSASignature(OID curveOID,
const uint8_t *msgHash, uint8_t msgHashLen,
const EncodedECPrivateKey& encodedPrivKey,
EncodedECDSASignature& encodedSig);
extern WEAVE_ERROR VerifyECDSASignature(OID curveOID,
const uint8_t *msgHash, uint8_t msgHashLen,
const EncodedECDSASignature& encodedSig,
const EncodedECPublicKey& encodedPubKey);
extern WEAVE_ERROR GenerateECDSASignature(OID curveOID,
const uint8_t *msgHash, uint8_t msgHashLen,
const EncodedECPrivateKey& encodedPrivKey,
uint8_t *fixedLenSig);
extern WEAVE_ERROR VerifyECDSASignature(OID curveOID,
const uint8_t *msgHash, uint8_t msgHashLen,
const uint8_t *fixedLenSig,
const EncodedECPublicKey& encodedPubKey);
extern WEAVE_ERROR GenerateECDHKey(OID curveOID, EncodedECPublicKey& encodedPubKey, EncodedECPrivateKey& encodedPrivKey);
extern WEAVE_ERROR ECDHComputeSharedSecret(OID curveOID, const EncodedECPublicKey& encodedPubKey, const EncodedECPrivateKey& encodedPrivKey,
uint8_t *sharedSecretBuf, uint16_t sharedSecretBufSize, uint16_t& sharedSecretLen);
extern WEAVE_ERROR GetCurveG(OID curveOID, EncodedECPublicKey& encodedPubKey);
// ============================================================
// OpenSSL-specific elliptic curve utility functions.
// ============================================================
#if WEAVE_WITH_OPENSSL
extern int GetCurveSize(const OID curveOID, const EC_GROUP *ecGroup);
extern WEAVE_ERROR GetECGroupForCurve(OID curveOID, EC_GROUP *& ecGroup);
extern 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);
extern WEAVE_ERROR EncodeX962ECPoint(OID curveOID, EC_GROUP *ecGroup, const EC_POINT *point, uint8_t *buf, uint16_t bufSize, uint16_t& encodedPointLen);
extern WEAVE_ERROR DecodeX962ECPoint(const uint8_t *encodedPoint, uint16_t encodedPointLen, EC_GROUP *group, EC_POINT *& point);
extern WEAVE_ERROR DecodeX962ECPoint(const uint8_t *encodedPoint, uint16_t encodedPointLen, BIGNUM *& x, BIGNUM *& y);
extern WEAVE_ERROR DecodeECKey(OID curveOID, const EncodedECPrivateKey *encodedPrivKey, const EncodedECPublicKey *encodedPubKey, EC_KEY *& ecKey);
extern WEAVE_ERROR EncodeECDSASignature(const ECDSA_SIG *sig, EncodedECDSASignature& encodedSig);
extern WEAVE_ERROR DecodeECDSASignature(const EncodedECDSASignature& encodedSig, ECDSA_SIG *& sig);
// EC Utility Functions with Fixed-Length ECDSA Signature Parameter
extern WEAVE_ERROR ECDSASigToFixedLenSig(OID curveOID, const ECDSA_SIG *ecSig, uint8_t *fixedLenSig);
extern WEAVE_ERROR FixedLenSigToECDSASig(OID curveOID, const uint8_t *fixedLenSig, ECDSA_SIG *& ecSig);
#endif // WEAVE_WITH_OPENSSL
// ============================================================
// Elliptic Curve JPAKE Class Declaration
// ============================================================
#if WEAVE_IS_ECJPAKE_ENABLED
#if WEAVE_CONFIG_USE_MICRO_ECC
class ECJPAKEStepPart
{
public:
uECC_word_t *Gx; /* G*x in step 1, G*(xa + xc + xd) in step 2 */
/* ZKP(x) or ZKP(xb * s) */
uECC_word_t *Gr; /* ZKP: G*r (r random) */
uECC_word_t *b; /* ZKP: b = r - x*h, h=hash(G, G*r, G*x, name) */
};
enum
{
kECJPAKE_HashLength = Platform::Security::SHA256::kHashLength,
kECJPAKE_MaxPasswordLength = 48,
kECJPAKE_MaxNameLength = 43,
};
// This check is needed because of the current limitation of uECC_vli_mmod function
#if kECJPAKE_HashLength > 2 * kuECC_MaxByteCount
#error "kECJPAKE_HashLength should be less or equal to (2 * kuECC_MaxByteCount)"
#endif
// This check is needed because of the current limitation of uECC_vli_mmod function
#if kECJPAKE_MaxPasswordLength > 2 * kuECC_MaxByteCount
#error "kECJPAKE_MaxPasswordLength should be less or equal to (2 * kuECC_MaxByteCount)"
#endif
typedef uint32_t EccPoint[2 * kuECC_MaxWordCount];
/* Points addition: result = left + right */
extern void uECC_point_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
uECC_Curve curve);
#endif // WEAVE_CONFIG_USE_MICRO_ECC
class EllipticCurveJPAKE
{
private:
#if WEAVE_CONFIG_USE_OPENSSL_ECC
struct ECJPAKE_CTX *ECJPAKECtx;
#endif // WEAVE_CONFIG_USE_OPENSSL_ECC
#if WEAVE_CONFIG_USE_MICRO_ECC
/* In the definition, (xa, xb, xc, xd) are Alice's (x1, x2, x3, x4)
* or Bob's (x3, x4, x1, x2) */
union
{
uECC_word_t Xb[kuECC_MaxWordCount]; /* Alice's x2 or Bob's x4 */
uint8_t SharedSecret[kECJPAKE_HashLength]; /* Calculated Shared Secret */
};
uECC_word_t XbS[kuECC_MaxWordCount]; /* Alice's (x2 * secret) or Bob's (x4 * secret) */
/* XbS field should be initialized with secret in VLI format */
EccPoint Gxd; /* Alice's G*x4 or Bob's G*x2 */
EccPoint Gxacd; /* Alice's G*(x1+x3+x4) or Bob's G*(x3+x1+x2) */
EccPoint Gxabc; /* Alice's G*(x1+x2+x3) or Bob's G*(x3+x4+x1) */
uint16_t LocalNameLen;
uint16_t PeerNameLen;
uint8_t LocalName[kECJPAKE_MaxNameLength]; /* Must be unique */
uint8_t PeerName[kECJPAKE_MaxNameLength];
uECC_Curve Curve; /* Elliptic Curve group */
#endif // WEAVE_CONFIG_USE_MICRO_ECC
public:
void Init(void);
void Shutdown(void);
void Reset(void);
WEAVE_ERROR 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 GenerateStep1(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen);
WEAVE_ERROR ProcessStep1(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen);
WEAVE_ERROR GenerateStep2(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen);
WEAVE_ERROR ProcessStep2(const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen);
uint8_t *GetSharedSecret(void);
int GetCurveSize(void);
private:
#if WEAVE_CONFIG_USE_MICRO_ECC
WEAVE_ERROR GenerateZeroKnowledgeProof(ECJPAKEStepPart *stepPart, const uECC_word_t *x, const EccPoint zkpG, const uint8_t *name, const uint16_t nameLen);
WEAVE_ERROR VerifyZeroKnowledgeProof(const ECJPAKEStepPart *stepPart, const EccPoint zkpG, const uint8_t *name, const uint16_t nameLen);
WEAVE_ERROR FindStepPartDataPointers(ECJPAKEStepPart *stepPart, const uint8_t *buf, const uint16_t bufSize, uint16_t& stepDataLen);
WEAVE_ERROR GenerateStepPart(ECJPAKEStepPart *stepPart, const uECC_word_t *x, const EccPoint G, const uint8_t *name, const uint16_t nameLen);
void ComputeSharedSecret(const EccPoint Gx);
#endif // WEAVE_CONFIG_USE_MICRO_ECC
};
#endif // WEAVE_IS_ECJPAKE_ENABLED
} // namespace Crypto
} // namespace Weave
} // namespace nl
#endif /* ELLIPTICCURVE_H_ */