Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit f5bf81f

Browse files
authored
Merge pull request #439 from openweave/feature/emargolis/RSA-Signature-Support
Add RSA signature support.
2 parents 2142449 + 1fd81e7 commit f5bf81f

File tree

5 files changed

+359
-1
lines changed

5 files changed

+359
-1
lines changed

src/include/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ $(nl_public_WeaveSupport_source_dirstem)/crypto/DRBG.h \
405405
$(nl_public_WeaveSupport_source_dirstem)/crypto/EllipticCurve.h \
406406
$(nl_public_WeaveSupport_source_dirstem)/crypto/HKDF.h \
407407
$(nl_public_WeaveSupport_source_dirstem)/crypto/HMAC.h \
408+
$(nl_public_WeaveSupport_source_dirstem)/crypto/RSA.h \
408409
$(nl_public_WeaveSupport_source_dirstem)/crypto/HashAlgos.h \
409410
$(nl_public_WeaveSupport_source_dirstem)/crypto/WeaveRNG.h \
410411
$(nl_public_WeaveSupport_source_dirstem)/crypto/WeaveCrypto.h \

src/lib/core/WeaveConfig.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,17 @@
990990
#define WEAVE_CONFIG_MAX_EC_BITS 256
991991
#endif // WEAVE_CONFIG_MAX_EC_BITS
992992

993+
/**
994+
* @def WEAVE_CONFIG_MAX_RSA_BITS
995+
*
996+
* @brief
997+
* The maximum size RSA modulus supported, in bits.
998+
*
999+
*/
1000+
#ifndef WEAVE_CONFIG_MAX_RSA_BITS
1001+
#define WEAVE_CONFIG_MAX_RSA_BITS 4096
1002+
#endif // WEAVE_CONFIG_MAX_RSA_BITS
1003+
9931004
/**
9941005
* @def WEAVE_CONFIG_MAX_PEER_NODES
9951006
*

src/lib/support/crypto/RSA.cpp

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
*
3+
* Copyright (c) 2019 Google LLC.
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* @file
21+
* General RSA utility functions.
22+
*
23+
*/
24+
25+
#include "RSA.h"
26+
#include <Weave/Core/WeaveEncoding.h>
27+
#include <Weave/Support/CodeUtils.h>
28+
29+
#if WEAVE_WITH_OPENSSL
30+
#include <openssl/bio.h>
31+
#include <openssl/x509.h>
32+
#include <openssl/rsa.h>
33+
#endif
34+
35+
namespace nl {
36+
namespace Weave {
37+
namespace Crypto {
38+
39+
using namespace nl::Weave::TLV;
40+
41+
/**
42+
* Compares with another RSA key.
43+
*
44+
* @param[in] other The EncodedRSAKey object with which key should be compared.
45+
*
46+
* @retval true The keys are equal.
47+
* @retval false The keys are not equal.
48+
*/
49+
bool EncodedRSAKey::IsEqual(const EncodedRSAKey& other) const
50+
{
51+
return (Key != NULL &&
52+
other.Key != NULL &&
53+
Len == other.Len &&
54+
memcmp(Key, other.Key, Len) == 0);
55+
}
56+
57+
/**
58+
* Compares with another RSA signature.
59+
*
60+
* @param[in] other The EncodedRSASignature object with which signature should be compared.
61+
*
62+
* @retval true The signatures are equal.
63+
* @retval false The signatures are not equal.
64+
*/
65+
bool EncodedRSASignature::IsEqual(const EncodedRSASignature& other) const
66+
{
67+
return (Sig != NULL &&
68+
other.Sig != NULL &&
69+
Len == other.Len &&
70+
memcmp(Sig, other.Sig, Len) == 0);
71+
}
72+
73+
/**
74+
* Reads the signature as a Weave RSASignature structure from the specified TLV reader.
75+
*
76+
* @param[in] reader The TLVReader object from which the encoded signature should
77+
* be read.
78+
*
79+
* @retval #WEAVE_NO_ERROR If the operation succeeded.
80+
* @retval other Other Weave error codes related to signature reading.
81+
*/
82+
WEAVE_ERROR EncodedRSASignature::ReadSignature(TLVReader& reader)
83+
{
84+
WEAVE_ERROR err;
85+
86+
VerifyOrExit(reader.GetType() == kTLVType_ByteString, err = WEAVE_ERROR_WRONG_TLV_TYPE);
87+
88+
err = reader.GetDataPtr(const_cast<const uint8_t *&>(Sig));
89+
SuccessOrExit(err);
90+
91+
Len = reader.GetLength();
92+
93+
exit:
94+
return err;
95+
}
96+
97+
#if WEAVE_WITH_OPENSSL
98+
99+
static int ShaNIDFromSigAlgoOID(OID sigAlgoOID)
100+
{
101+
int nid;
102+
103+
// Current implementation only supports SHA256WithRSAEncryption signature algorithm.
104+
if (sigAlgoOID == ASN1::kOID_SigAlgo_SHA256WithRSAEncryption)
105+
nid = NID_sha256;
106+
else
107+
nid = NID_undef;
108+
109+
return nid;
110+
}
111+
112+
/**
113+
* Generate and encode a Weave RSA signature
114+
*
115+
* Computes an RSA signature using a given X509 encoded RSA private key and message hash
116+
* and writes the signature as a Weave RSASignature structure to the specified TLV writer
117+
* with the given tag.
118+
*
119+
* @param[in] sigAlgoOID Algorithm OID to be used to generate RSA signature.
120+
* @param[in] writer The TLVWriter object to which the encoded signature should
121+
* be written.
122+
* @param[in] tag TLV tag to be associated with the encoded signature structure.
123+
* @param[in] hash A buffer containing the hash of the data to be signed.
124+
* @param[in] hashLen The length in bytes of the data hash.
125+
* @param[in] keyDER A buffer containing the private key to be used to generate
126+
* the signature. The private key is expected to be encoded as
127+
* an X509 RSA private key structure.
128+
* @param[in] keyDERLen The length in bytes of the encoded private key.
129+
*
130+
* @retval #WEAVE_NO_ERROR If the operation succeeded.
131+
* @retval other Other Weave error codes related to decoding the private key,
132+
* generating the signature or encoding the signature.
133+
*
134+
*/
135+
WEAVE_ERROR GenerateAndEncodeWeaveRSASignature(OID sigAlgoOID,
136+
TLVWriter& writer, uint64_t tag,
137+
const uint8_t * hash, uint8_t hashLen,
138+
const uint8_t * keyDER, uint16_t keyDERLen)
139+
{
140+
WEAVE_ERROR err;
141+
RSA *rsa = NULL;
142+
uint8_t sigBuf[EncodedRSASignature::kMaxValueLength];
143+
uint32_t sigLen;
144+
EncodedRSASignature sig;
145+
int shaNID;
146+
147+
shaNID = ShaNIDFromSigAlgoOID(sigAlgoOID);
148+
VerifyOrExit(shaNID != NID_undef, err = WEAVE_ERROR_UNSUPPORTED_SIGNATURE_TYPE);
149+
150+
rsa = d2i_RSAPrivateKey(NULL, &keyDER, keyDERLen);
151+
VerifyOrExit(rsa != NULL, err = WEAVE_ERROR_NO_MEMORY);
152+
153+
if (RSA_sign(shaNID, hash, hashLen, sigBuf, &sigLen, rsa) == 0)
154+
ExitNow(err = WEAVE_ERROR_NO_MEMORY);
155+
156+
sig.Sig = sigBuf;
157+
sig.Len = sigLen;
158+
159+
// Encode an RSASignature value into the supplied writer.
160+
err = sig.WriteSignature(writer, tag);
161+
SuccessOrExit(err);
162+
163+
exit:
164+
if (NULL != rsa) RSA_free(rsa);
165+
166+
return err;
167+
}
168+
169+
/**
170+
* Verify a Weave RSA signature.
171+
*
172+
* Verifies an RSA signature using given data hash and an X509 encoded RSA certificate containing
173+
* the public key to be used to verify the signature.
174+
*
175+
* @param[in] sigAlgoOID Algorithm OID to be used to generate RSA signature.
176+
* @param[in] hash A buffer containing the hash of the data to be signed.
177+
* @param[in] hashLen The length in bytes of the data hash.
178+
* @param[in] sig Encoded RSA signature to be verified.
179+
* @param[in] certDER A buffer containing the certificate with public key to be used
180+
* to verify the signature. The certificate is expected to be DER
181+
* encoded an X509 RSA structure.
182+
* @param[in] certDERLen The length in bytes of the encoded certificate.
183+
*
184+
* @retval #WEAVE_NO_ERROR If the operation succeeded.
185+
*/
186+
WEAVE_ERROR VerifyRSASignature(OID sigAlgoOID,
187+
const uint8_t * hash, uint8_t hashLen,
188+
const EncodedRSASignature& sig,
189+
const uint8_t * certDER, uint16_t certDERLen)
190+
{
191+
WEAVE_ERROR err = WEAVE_NO_ERROR;
192+
BIO *certBuf = NULL;
193+
X509 *cert = NULL;
194+
EVP_PKEY *pubKey = NULL;
195+
int shaNID;
196+
int res;
197+
198+
shaNID = ShaNIDFromSigAlgoOID(sigAlgoOID);
199+
VerifyOrExit(shaNID != NID_undef, err = WEAVE_ERROR_UNSUPPORTED_SIGNATURE_TYPE);
200+
201+
certBuf = BIO_new_mem_buf(certDER, certDERLen);
202+
VerifyOrExit(certBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
203+
204+
cert = d2i_X509_bio(certBuf, NULL);
205+
VerifyOrExit(cert != NULL, err = WEAVE_ERROR_NO_MEMORY);
206+
207+
pubKey = X509_get_pubkey(cert);
208+
VerifyOrExit(pubKey != NULL, err = WEAVE_ERROR_NO_MEMORY);
209+
210+
// Verify that the public key from the certificate is an RSA key.
211+
VerifyOrExit(EVP_PKEY_RSA == EVP_PKEY_base_id(pubKey), err = WEAVE_ERROR_WRONG_KEY_TYPE);
212+
213+
res = RSA_verify(shaNID, hash, hashLen, sig.Sig, sig.Len, EVP_PKEY_get1_RSA(pubKey));
214+
VerifyOrExit(res == 1, err = WEAVE_ERROR_INVALID_SIGNATURE);
215+
216+
exit:
217+
if (NULL != pubKey) EVP_PKEY_free(pubKey);
218+
if (NULL != cert) X509_free(cert);
219+
if (NULL != certBuf) BIO_free(certBuf);
220+
221+
return err;
222+
}
223+
224+
#endif // WEAVE_WITH_OPENSSL
225+
226+
// ==================== Documentation for Inline Public Members ====================
227+
228+
/**
229+
* @fn WEAVE_ERROR EncodedRSASignature::WriteSignature(TLVWriter& writer, uint64_t tag) const
230+
*
231+
* Writes the signature as a Weave RSASignature structure to the specified TLV writer
232+
* with the given tag.
233+
*
234+
* @param[in] writer The TLVWriter object to which the encoded signature should
235+
* be written.
236+
* @param[in] tag TLV tag to be associated with the encoded signature structure.
237+
238+
* @retval #WEAVE_NO_ERROR If the operation succeeded.
239+
* @retval other Other Weave error codes related to signature writing.
240+
*/
241+
242+
} // namespace Crypto
243+
} // namespace Weave
244+
} // namespace nl

src/lib/support/crypto/RSA.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
*
3+
* Copyright (c) 2019 Google LLC.
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* @file
21+
* This file defines types, objects, and methods for working with
22+
* RSA public and private keys and RSA signatures.
23+
*
24+
*/
25+
26+
#ifndef RSA_H_
27+
#define RSA_H_
28+
29+
#include "WeaveCrypto.h"
30+
#include <Weave/Core/WeaveTLV.h>
31+
#include <Weave/Support/ASN1.h>
32+
#include <Weave/Support/MathUtils.h>
33+
34+
namespace nl {
35+
namespace Weave {
36+
namespace Crypto {
37+
38+
using nl::Weave::TLV::TLVReader;
39+
using nl::Weave::TLV::TLVWriter;
40+
using nl::Weave::ASN1::OID;
41+
42+
class EncodedRSAKey
43+
{
44+
public:
45+
enum
46+
{
47+
kMaxValueLength = Platform::BitsToByteLength(WEAVE_CONFIG_MAX_RSA_BITS + 1)
48+
};
49+
50+
uint8_t *Key; // ASN.1 DER Integer value format.
51+
uint16_t Len;
52+
53+
bool IsEqual(const EncodedRSAKey& other) const;
54+
};
55+
56+
class EncodedRSASignature
57+
{
58+
public:
59+
enum
60+
{
61+
kMaxValueLength = Platform::BitsToByteLength(WEAVE_CONFIG_MAX_RSA_BITS)
62+
};
63+
64+
uint8_t *Sig; // ASN.1 DER Integer value format
65+
uint16_t Len;
66+
67+
bool IsEqual(const EncodedRSASignature& other) const;
68+
69+
WEAVE_ERROR ReadSignature(TLVReader& reader);
70+
WEAVE_ERROR WriteSignature(TLVWriter& writer, uint64_t tag) const;
71+
};
72+
73+
inline WEAVE_ERROR EncodedRSASignature::WriteSignature(TLVWriter& writer, uint64_t tag) const
74+
{
75+
return writer.PutBytes(tag, Sig, Len);
76+
}
77+
78+
// =============================================================
79+
// Primary RSA utility functions used by Weave security code.
80+
// =============================================================
81+
82+
#if WEAVE_WITH_OPENSSL
83+
84+
extern WEAVE_ERROR GenerateAndEncodeWeaveRSASignature(OID sigAlgoOID,
85+
TLVWriter& writer, uint64_t tag,
86+
const uint8_t * hash, uint8_t hashLen,
87+
const uint8_t * keyDER, uint16_t keyDERLen);
88+
89+
extern WEAVE_ERROR VerifyRSASignature(OID sigAlgoOID,
90+
const uint8_t * hash, uint8_t hashLen,
91+
const EncodedRSASignature& sig,
92+
const uint8_t * certDER, uint16_t certDERLen);
93+
94+
#endif // WEAVE_WITH_OPENSSL
95+
96+
} // namespace Crypto
97+
} // namespace Weave
98+
} // namespace nl
99+
100+
#endif /* RSA_H_ */

src/lib/support/gen-oid-table.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ def identity(n):
9999
( "SigAlgo", "ECDSAWithSHA1", 4, [ iso(1), member_body(2), us(840), ansi_X9_62(10045), signatures(4), 1 ] ),
100100
( "SigAlgo", "ECDSAWithSHA256", 5, [ iso(1), member_body(2), us(840), ansi_X9_62(10045), signatures(4), 3, 2 ] ),
101101
# RFC 4231
102-
( "SigAlgo", "HMACWithSHA256", 6, [ iso(1), member_body(2), us(840), rsadsi(113549), digest_algorithm(2), 9 ] ),
102+
( "SigAlgo", "HMACWithSHA256", 6, [ iso(1), member_body(2), us(840), rsadsi(113549), digest_algorithm(2), 9 ] ),
103+
# RFC 4055
104+
( "SigAlgo", "SHA256WithRSAEncryption", 7, [ iso(1), member_body(2), us(840), rsadsi(113549), pkcs(1), pkcs1(1), 11 ] ),
103105

104106
# X.509 Distinguished Name Attribute Types
105107
# WARNING -- Assign no values higher than 127.

0 commit comments

Comments
 (0)