Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2022 Project CHIP Authors
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 implements methods for generating CHIP X.509 certificate.
22 : *
23 : */
24 :
25 : #ifndef __STDC_LIMIT_MACROS
26 : #define __STDC_LIMIT_MACROS
27 : #endif
28 :
29 : #include <algorithm>
30 : #include <initializer_list>
31 : #include <inttypes.h>
32 : #include <stddef.h>
33 :
34 : #include <credentials/CHIPCert_Internal.h>
35 : #include <lib/asn1/ASN1.h>
36 : #include <lib/asn1/ASN1Macros.h>
37 : #include <lib/core/CHIPCore.h>
38 : #include <lib/core/CHIPSafeCasts.h>
39 : #include <lib/support/CodeUtils.h>
40 : #include <lib/support/DLLUtil.h>
41 : #include <protocols/Protocols.h>
42 :
43 : namespace chip {
44 : namespace Credentials {
45 :
46 : using namespace chip::ASN1;
47 : using namespace chip::Crypto;
48 : using namespace chip::Protocols;
49 :
50 : namespace {
51 :
52 : enum IsCACert
53 : {
54 : kCACert,
55 : kNotCACert,
56 : };
57 :
58 147 : CHIP_ERROR EncodeSubjectPublicKeyInfo(const Crypto::P256PublicKey & pubkey, ASN1Writer & writer)
59 : {
60 147 : CHIP_ERROR err = CHIP_NO_ERROR;
61 :
62 147 : ASN1_START_SEQUENCE
63 : {
64 147 : ASN1_START_SEQUENCE
65 : {
66 147 : ASN1_ENCODE_OBJECT_ID(kOID_PubKeyAlgo_ECPublicKey);
67 147 : ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1);
68 : }
69 147 : ASN1_END_SEQUENCE;
70 :
71 147 : ReturnErrorOnFailure(writer.PutBitString(0, pubkey, static_cast<uint8_t>(pubkey.Length())));
72 : }
73 147 : ASN1_END_SEQUENCE;
74 :
75 147 : exit:
76 147 : return err;
77 : }
78 :
79 142 : CHIP_ERROR EncodeAuthorityKeyIdentifierExtension(const Crypto::P256PublicKey & pubkey, ASN1Writer & writer)
80 : {
81 142 : CHIP_ERROR err = CHIP_NO_ERROR;
82 :
83 142 : ASN1_START_SEQUENCE
84 : {
85 142 : ASN1_ENCODE_OBJECT_ID(kOID_Extension_AuthorityKeyIdentifier);
86 :
87 142 : ASN1_START_OCTET_STRING_ENCAPSULATED
88 : {
89 142 : ASN1_START_SEQUENCE
90 : {
91 : uint8_t keyid[kSHA1_Hash_Length];
92 142 : ReturnErrorOnFailure(Crypto::Hash_SHA1(pubkey, pubkey.Length(), keyid));
93 :
94 142 : ReturnErrorOnFailure(
95 : writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, keyid, static_cast<uint8_t>(sizeof(keyid))));
96 : }
97 142 : ASN1_END_SEQUENCE;
98 : }
99 142 : ASN1_END_ENCAPSULATED;
100 : }
101 142 : ASN1_END_SEQUENCE;
102 :
103 142 : exit:
104 142 : return err;
105 : }
106 :
107 142 : CHIP_ERROR EncodeSubjectKeyIdentifierExtension(const Crypto::P256PublicKey & pubkey, ASN1Writer & writer)
108 : {
109 142 : CHIP_ERROR err = CHIP_NO_ERROR;
110 :
111 142 : ASN1_START_SEQUENCE
112 : {
113 142 : ASN1_ENCODE_OBJECT_ID(kOID_Extension_SubjectKeyIdentifier);
114 :
115 142 : ASN1_START_OCTET_STRING_ENCAPSULATED
116 : {
117 : uint8_t keyid[kSHA1_Hash_Length];
118 142 : ReturnErrorOnFailure(Crypto::Hash_SHA1(pubkey, pubkey.Length(), keyid));
119 :
120 142 : ReturnErrorOnFailure(writer.PutOctetString(keyid, static_cast<uint8_t>(sizeof(keyid))));
121 : }
122 142 : ASN1_END_ENCAPSULATED;
123 : }
124 142 : ASN1_END_SEQUENCE;
125 :
126 142 : exit:
127 142 : return err;
128 : }
129 :
130 65 : CHIP_ERROR EncodeExtKeyUsageExtension(std::initializer_list<OID> keyPurposeOIDs, ASN1Writer & writer)
131 : {
132 65 : CHIP_ERROR err = CHIP_NO_ERROR;
133 65 : ASN1_START_SEQUENCE
134 : {
135 65 : ASN1_ENCODE_OBJECT_ID(kOID_Extension_ExtendedKeyUsage);
136 :
137 : // ExtKeyUsage extension MUST be marked as critical.
138 65 : ASN1_ENCODE_BOOLEAN(true);
139 65 : ASN1_START_OCTET_STRING_ENCAPSULATED
140 : {
141 65 : ASN1_START_SEQUENCE
142 : {
143 195 : for (auto && oid : keyPurposeOIDs)
144 : {
145 130 : ASN1_ENCODE_OBJECT_ID(oid);
146 : }
147 : }
148 65 : ASN1_END_SEQUENCE;
149 : }
150 65 : ASN1_END_ENCAPSULATED;
151 : }
152 65 : ASN1_END_SEQUENCE;
153 :
154 65 : exit:
155 65 : return err;
156 : }
157 :
158 147 : CHIP_ERROR EncodeKeyUsageExtension(BitFlags<KeyUsageFlags> keyUsageFlags, ASN1Writer & writer)
159 : {
160 147 : CHIP_ERROR err = CHIP_NO_ERROR;
161 147 : ASN1_START_SEQUENCE
162 : {
163 147 : ASN1_ENCODE_OBJECT_ID(kOID_Extension_KeyUsage);
164 :
165 : // KeyUsage extension MUST be marked as critical.
166 147 : ASN1_ENCODE_BOOLEAN(true);
167 147 : ASN1_START_OCTET_STRING_ENCAPSULATED
168 : {
169 147 : ASN1_ENCODE_BIT_STRING(keyUsageFlags.Raw());
170 : }
171 147 : ASN1_END_ENCAPSULATED;
172 : }
173 147 : ASN1_END_SEQUENCE;
174 :
175 147 : exit:
176 147 : return err;
177 : }
178 :
179 147 : CHIP_ERROR EncodeIsCAExtension(IsCACert isCA, ASN1Writer & writer)
180 : {
181 147 : CHIP_ERROR err = CHIP_NO_ERROR;
182 147 : ASN1_START_SEQUENCE
183 : {
184 147 : ASN1_ENCODE_OBJECT_ID(kOID_Extension_BasicConstraints);
185 :
186 : // BasicConstraints extension MUST be marked as critical.
187 147 : ASN1_ENCODE_BOOLEAN(true);
188 :
189 147 : ASN1_START_OCTET_STRING_ENCAPSULATED
190 : {
191 147 : ASN1_START_SEQUENCE
192 : {
193 : // cA BOOLEAN
194 147 : if (isCA == kCACert)
195 : {
196 : // Encode the boolean only if isCA is true
197 82 : ASN1_ENCODE_BOOLEAN(true);
198 : }
199 : }
200 147 : ASN1_END_SEQUENCE;
201 : }
202 147 : ASN1_END_ENCAPSULATED;
203 : }
204 147 : ASN1_END_SEQUENCE;
205 :
206 147 : exit:
207 147 : return err;
208 : }
209 :
210 82 : CHIP_ERROR EncodeCASpecificExtensions(ASN1Writer & writer)
211 : {
212 82 : ReturnErrorOnFailure(EncodeIsCAExtension(kCACert, writer));
213 82 : ReturnErrorOnFailure(
214 : EncodeKeyUsageExtension(BitFlags<KeyUsageFlags>(KeyUsageFlags::kKeyCertSign, KeyUsageFlags::kCRLSign), writer));
215 82 : return CHIP_NO_ERROR;
216 : }
217 :
218 60 : CHIP_ERROR EncodeNOCSpecificExtensions(ASN1Writer & writer)
219 : {
220 60 : ReturnErrorOnFailure(EncodeIsCAExtension(kNotCACert, writer));
221 60 : ReturnErrorOnFailure(EncodeKeyUsageExtension(KeyUsageFlags::kDigitalSignature, writer));
222 60 : ReturnErrorOnFailure(EncodeExtKeyUsageExtension({ kOID_KeyPurpose_ClientAuth, kOID_KeyPurpose_ServerAuth }, writer));
223 60 : return CHIP_NO_ERROR;
224 : }
225 :
226 142 : CHIP_ERROR EncodeFutureExtension(const Optional<FutureExtension> & futureExt, ASN1Writer & writer)
227 : {
228 142 : CHIP_ERROR err = CHIP_NO_ERROR;
229 :
230 142 : VerifyOrReturnError(futureExt.HasValue(), CHIP_NO_ERROR);
231 :
232 6 : ASN1_START_SEQUENCE
233 : {
234 6 : ReturnErrorOnFailure(writer.PutObjectId(futureExt.Value().OID.data(), static_cast<uint16_t>(futureExt.Value().OID.size())));
235 :
236 6 : ASN1_START_OCTET_STRING_ENCAPSULATED
237 : {
238 6 : ReturnErrorOnFailure(writer.PutOctetString(futureExt.Value().Extension.data(),
239 : static_cast<uint16_t>(futureExt.Value().Extension.size())));
240 : }
241 6 : ASN1_END_ENCAPSULATED;
242 : }
243 6 : ASN1_END_SEQUENCE;
244 :
245 6 : exit:
246 6 : return err;
247 : }
248 :
249 142 : CHIP_ERROR EncodeExtensions(bool isCA, const Crypto::P256PublicKey & SKI, const Crypto::P256PublicKey & AKI,
250 : const Optional<FutureExtension> & futureExt, ASN1Writer & writer)
251 : {
252 142 : CHIP_ERROR err = CHIP_NO_ERROR;
253 :
254 142 : ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
255 : {
256 142 : ASN1_START_SEQUENCE
257 : {
258 142 : if (isCA)
259 : {
260 82 : ReturnErrorOnFailure(EncodeCASpecificExtensions(writer));
261 : }
262 : else
263 : {
264 60 : ReturnErrorOnFailure(EncodeNOCSpecificExtensions(writer));
265 : }
266 :
267 142 : ReturnErrorOnFailure(EncodeSubjectKeyIdentifierExtension(SKI, writer));
268 :
269 142 : ReturnErrorOnFailure(EncodeAuthorityKeyIdentifierExtension(AKI, writer));
270 :
271 142 : ReturnErrorOnFailure(EncodeFutureExtension(futureExt, writer));
272 : }
273 142 : ASN1_END_SEQUENCE;
274 : }
275 142 : ASN1_END_CONSTRUCTED;
276 :
277 142 : exit:
278 142 : return err;
279 : }
280 :
281 147 : CHIP_ERROR EncodeValidity(uint32_t validityStart, uint32_t validityEnd, ASN1Writer & writer)
282 : {
283 147 : CHIP_ERROR err = CHIP_NO_ERROR;
284 : ASN1UniversalTime asn1Time;
285 :
286 147 : ASN1_START_SEQUENCE
287 : {
288 147 : ReturnErrorOnFailure(ChipEpochToASN1Time(validityStart, asn1Time));
289 147 : ASN1_ENCODE_TIME(asn1Time);
290 :
291 147 : ReturnErrorOnFailure(ChipEpochToASN1Time(validityEnd, asn1Time));
292 147 : ASN1_ENCODE_TIME(asn1Time);
293 : }
294 147 : ASN1_END_SEQUENCE;
295 :
296 147 : exit:
297 147 : return err;
298 : }
299 :
300 71 : CHIP_ERROR EncodeChipECDSASignature(Crypto::P256ECDSASignature & signature, ASN1Writer & writer)
301 : {
302 71 : CHIP_ERROR err = CHIP_NO_ERROR;
303 :
304 71 : ASN1_START_BIT_STRING_ENCAPSULATED
305 : {
306 : // Convert RAW signature to DER when generating X509 certs.
307 71 : P256ECDSASignatureSpan raw_sig(signature.Bytes());
308 71 : ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(raw_sig, writer));
309 : }
310 71 : ASN1_END_ENCAPSULATED;
311 :
312 71 : exit:
313 71 : return err;
314 : }
315 :
316 144 : CHIP_ERROR EncodeTBSCert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey,
317 : const Crypto::P256PublicKey & issuerPubkey, ASN1Writer & writer)
318 : {
319 144 : CHIP_ERROR err = CHIP_NO_ERROR;
320 : CertType certType;
321 : bool isCA;
322 :
323 144 : VerifyOrReturnError(requestParams.SerialNumber >= 0, CHIP_ERROR_INVALID_ARGUMENT);
324 142 : VerifyOrReturnError(requestParams.ValidityEnd == kNullCertTime || requestParams.ValidityEnd >= requestParams.ValidityStart,
325 : CHIP_ERROR_INVALID_ARGUMENT);
326 :
327 142 : ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
328 142 : isCA = (certType == CertType::kICA || certType == CertType::kRoot);
329 :
330 142 : ASN1_START_SEQUENCE
331 : {
332 : // version [0] EXPLICIT Version DEFAULT v1
333 142 : ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
334 : {
335 : // Version ::= INTEGER { v1(0), v2(1), v3(2) }
336 142 : ASN1_ENCODE_INTEGER(2);
337 : }
338 142 : ASN1_END_CONSTRUCTED;
339 :
340 142 : ReturnErrorOnFailure(writer.PutInteger(requestParams.SerialNumber));
341 :
342 142 : ASN1_START_SEQUENCE
343 : {
344 142 : ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
345 : }
346 142 : ASN1_END_SEQUENCE;
347 :
348 : // issuer Name
349 142 : ReturnErrorOnFailure(requestParams.IssuerDN.EncodeToASN1(writer));
350 :
351 : // validity Validity,
352 142 : ReturnErrorOnFailure(EncodeValidity(requestParams.ValidityStart, requestParams.ValidityEnd, writer));
353 :
354 : // subject Name
355 142 : ReturnErrorOnFailure(requestParams.SubjectDN.EncodeToASN1(writer));
356 :
357 142 : ReturnErrorOnFailure(EncodeSubjectPublicKeyInfo(subjectPubkey, writer));
358 :
359 : // certificate extensions
360 142 : ReturnErrorOnFailure(EncodeExtensions(isCA, subjectPubkey, issuerPubkey, requestParams.FutureExt, writer));
361 : }
362 142 : ASN1_END_SEQUENCE;
363 :
364 142 : exit:
365 142 : return err;
366 : }
367 :
368 : } // namespace
369 :
370 5 : CHIP_ERROR EncodeNetworkIdentityTBSCert(const P256PublicKey & pubkey, ASN1Writer & writer)
371 : {
372 5 : CHIP_ERROR err = CHIP_NO_ERROR;
373 5 : ChipDN issuerAndSubject;
374 5 : InitNetworkIdentitySubject(issuerAndSubject);
375 :
376 5 : ASN1_START_SEQUENCE
377 : {
378 : // version [0] EXPLICIT Version DEFAULT v1
379 5 : ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
380 : {
381 5 : ASN1_ENCODE_INTEGER(2); // Version ::= INTEGER { v1(0), v2(1), v3(2) }
382 : }
383 5 : ASN1_END_CONSTRUCTED;
384 :
385 5 : ReturnErrorOnFailure(writer.PutInteger(kNetworkIdentitySerialNumber));
386 :
387 5 : ASN1_START_SEQUENCE
388 : {
389 5 : ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
390 : }
391 5 : ASN1_END_SEQUENCE;
392 :
393 : // issuer Name
394 5 : ReturnErrorOnFailure(issuerAndSubject.EncodeToASN1(writer));
395 :
396 : // validity Validity,
397 5 : ReturnErrorOnFailure(EncodeValidity(kNetworkIdentityNotBeforeTime, kNetworkIdentityNotAfterTime, writer));
398 :
399 : // subject Name
400 5 : ReturnErrorOnFailure(issuerAndSubject.EncodeToASN1(writer));
401 :
402 5 : ReturnErrorOnFailure(EncodeSubjectPublicKeyInfo(pubkey, writer));
403 :
404 : // certificate extensions
405 5 : ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
406 : {
407 5 : ASN1_START_SEQUENCE
408 : {
409 5 : EncodeIsCAExtension(kNotCACert, writer);
410 5 : EncodeKeyUsageExtension(KeyUsageFlags::kDigitalSignature, writer);
411 5 : EncodeExtKeyUsageExtension({ kOID_KeyPurpose_ClientAuth, kOID_KeyPurpose_ServerAuth }, writer);
412 : }
413 5 : ASN1_END_SEQUENCE;
414 : }
415 5 : ASN1_END_CONSTRUCTED;
416 : }
417 5 : ASN1_END_SEQUENCE;
418 :
419 5 : exit:
420 5 : return err;
421 5 : }
422 :
423 73 : CHIP_ERROR NewChipX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey,
424 : const Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert)
425 : {
426 73 : CHIP_ERROR err = CHIP_NO_ERROR;
427 : ASN1Writer writer;
428 73 : writer.Init(x509Cert);
429 :
430 73 : ReturnErrorOnFailure(EncodeTBSCert(requestParams, subjectPubkey, issuerKeypair.Pubkey(), writer));
431 :
432 71 : Crypto::P256ECDSASignature signature;
433 71 : ReturnErrorOnFailure(issuerKeypair.ECDSA_sign_msg(x509Cert.data(), writer.GetLengthWritten(), signature));
434 :
435 71 : writer.Init(x509Cert);
436 :
437 71 : ASN1_START_SEQUENCE
438 : {
439 71 : ReturnErrorOnFailure(EncodeTBSCert(requestParams, subjectPubkey, issuerKeypair.Pubkey(), writer));
440 :
441 71 : ASN1_START_SEQUENCE
442 : {
443 71 : ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
444 : }
445 71 : ASN1_END_SEQUENCE;
446 :
447 71 : ReturnErrorOnFailure(EncodeChipECDSASignature(signature, writer));
448 : }
449 71 : ASN1_END_SEQUENCE;
450 :
451 71 : x509Cert.reduce_size(writer.GetLengthWritten());
452 :
453 71 : exit:
454 71 : return err;
455 71 : }
456 :
457 25 : DLL_EXPORT CHIP_ERROR NewRootX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256Keypair & issuerKeypair,
458 : MutableByteSpan & x509Cert)
459 : {
460 : CertType certType;
461 :
462 25 : ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
463 25 : VerifyOrReturnError(certType == CertType::kRoot, CHIP_ERROR_INVALID_ARGUMENT);
464 24 : VerifyOrReturnError(requestParams.SubjectDN.IsEqual(requestParams.IssuerDN), CHIP_ERROR_INVALID_ARGUMENT);
465 :
466 23 : return NewChipX509Cert(requestParams, issuerKeypair.Pubkey(), issuerKeypair, x509Cert);
467 : }
468 :
469 21 : DLL_EXPORT CHIP_ERROR NewICAX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey,
470 : const Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert)
471 : {
472 : CertType certType;
473 :
474 21 : ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
475 21 : VerifyOrReturnError(certType == CertType::kICA, CHIP_ERROR_INVALID_ARGUMENT);
476 :
477 20 : ReturnErrorOnFailure(requestParams.IssuerDN.GetCertType(certType));
478 20 : VerifyOrReturnError(certType == CertType::kRoot, CHIP_ERROR_INVALID_ARGUMENT);
479 :
480 20 : return NewChipX509Cert(requestParams, subjectPubkey, issuerKeypair, x509Cert);
481 : }
482 :
483 33 : DLL_EXPORT CHIP_ERROR NewNodeOperationalX509Cert(const X509CertRequestParams & requestParams,
484 : const Crypto::P256PublicKey & subjectPubkey,
485 : const Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert)
486 : {
487 : CertType certType;
488 :
489 33 : ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
490 32 : VerifyOrReturnError(certType == CertType::kNode, CHIP_ERROR_INVALID_ARGUMENT);
491 :
492 31 : ReturnErrorOnFailure(requestParams.IssuerDN.GetCertType(certType));
493 31 : VerifyOrReturnError(certType == CertType::kICA || certType == CertType::kRoot, CHIP_ERROR_INVALID_ARGUMENT);
494 :
495 30 : return NewChipX509Cert(requestParams, subjectPubkey, issuerKeypair, x509Cert);
496 : }
497 :
498 : } // namespace Credentials
499 : } // namespace chip
|