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