Apply Upstream code (2021-03-15)
[platform/upstream/connectedhomeip.git] / src / credentials / CHIPCertFromX509.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    Copyright (c) 2013-2017 Nest Labs, Inc.
5  *    All rights reserved.
6  *
7  *    Licensed under the Apache License, Version 2.0 (the "License");
8  *    you may not use this file except in compliance with the License.
9  *    You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *    Unless required by applicable law or agreed to in writing, software
14  *    distributed under the License is distributed on an "AS IS" BASIS,
15  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *    See the License for the specific language governing permissions and
17  *    limitations under the License.
18  */
19
20 /**
21  *    @file
22  *      This file implements methods for converting a standard X.509
23  *      certificate to a CHIP TLV-encoded certificate.
24  *
25  */
26
27 #ifndef __STDC_LIMIT_MACROS
28 #define __STDC_LIMIT_MACROS
29 #endif
30
31 #include <stddef.h>
32
33 #include <asn1/ASN1.h>
34 #include <asn1/ASN1Macros.h>
35 #include <core/CHIPCore.h>
36 #include <core/CHIPSafeCasts.h>
37 #include <core/CHIPTLV.h>
38 #include <credentials/CHIPCert.h>
39 #include <protocols/Protocols.h>
40 #include <support/CodeUtils.h>
41
42 namespace chip {
43 namespace Credentials {
44
45 using namespace chip::ASN1;
46 using namespace chip::TLV;
47 using namespace chip::Protocols;
48
49 static ASN1_ERROR ParseChipIdAttribute(ASN1Reader & reader, uint64_t & chipIdOut)
50 {
51     ASN1_ERROR err        = ASN1_NO_ERROR;
52     const uint8_t * value = nullptr;
53
54     VerifyOrExit(reader.GetValueLen() == kChipIdUTF8Length, err = ASN1_ERROR_INVALID_ENCODING);
55
56     value = reader.GetValue();
57     VerifyOrExit(value != nullptr, err = ASN1_ERROR_INVALID_ENCODING);
58
59     chipIdOut = 0;
60
61     for (uint32_t i = 0; i < kChipIdUTF8Length; i++)
62     {
63         chipIdOut <<= 4;
64         uint8_t ch = value[i];
65         if (ch >= '0' && ch <= '9')
66         {
67             chipIdOut |= (ch - '0');
68         }
69         // CHIP Id attribute encodings only support uppercase chars.
70         else if (ch >= 'A' && ch <= 'F')
71         {
72             chipIdOut |= (ch - 'A' + 10);
73         }
74         else
75         {
76             ExitNow(err = ASN1_ERROR_INVALID_ENCODING);
77         }
78     }
79
80 exit:
81     return err;
82 }
83
84 static CHIP_ERROR ConvertDistinguishedName(ASN1Reader & reader, TLVWriter & writer, uint64_t tag)
85 {
86     CHIP_ERROR err;
87     TLVType outerContainer;
88     OID attrOID;
89
90     err = writer.StartContainer(tag, kTLVType_List, outerContainer);
91     SuccessOrExit(err);
92
93     // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
94     ASN1_PARSE_ENTER_SEQUENCE
95     {
96         while ((err = reader.Next()) == ASN1_NO_ERROR)
97         {
98             // RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
99             ASN1_ENTER_SET
100             {
101                 // AttributeTypeAndValue ::= SEQUENCE
102                 ASN1_PARSE_ENTER_SEQUENCE
103                 {
104                     // type AttributeType
105                     // AttributeType ::= OBJECT IDENTIFIER
106                     ASN1_PARSE_OBJECT_ID(attrOID);
107                     VerifyOrExit(GetOIDCategory(attrOID) == kOIDCategory_AttributeType, err = ASN1_ERROR_INVALID_ENCODING);
108
109                     // AttributeValue ::= ANY -- DEFINED BY AttributeType
110                     ASN1_PARSE_ANY;
111
112                     // Can only support UTF8String, PrintableString and IA5String.
113                     VerifyOrExit(reader.GetClass() == kASN1TagClass_Universal &&
114                                      (reader.GetTag() == kASN1UniversalTag_PrintableString ||
115                                       reader.GetTag() == kASN1UniversalTag_UTF8String ||
116                                       reader.GetTag() == kASN1UniversalTag_IA5String),
117                                  err = ASN1_ERROR_UNSUPPORTED_ENCODING);
118
119                     // CHIP id attributes must be UTF8Strings.
120                     if (IsChipIdX509Attr(attrOID))
121                     {
122                         VerifyOrExit(reader.GetTag() == kASN1UniversalTag_UTF8String, err = ASN1_ERROR_INVALID_ENCODING);
123                     }
124
125                     // Derive the TLV tag number from the enum value assigned to the attribute type OID. For attributes that can be
126                     // either UTF8String or PrintableString, use the high bit in the tag number to distinguish the two.
127                     uint8_t tlvTagNum = GetOIDEnum(attrOID);
128                     if (reader.GetTag() == kASN1UniversalTag_PrintableString)
129                     {
130                         tlvTagNum |= 0x80;
131                     }
132
133                     // If the attribute is a CHIP-defined attribute that contains a 64-bit CHIP id...
134                     if (IsChipIdX509Attr(attrOID))
135                     {
136                         // Parse the attribute string into a 64-bit CHIP id.
137                         uint64_t chipId;
138                         err = ParseChipIdAttribute(reader, chipId);
139                         SuccessOrExit(err);
140
141                         // Write the CHIP id into the TLV.
142                         err = writer.Put(ContextTag(tlvTagNum), chipId);
143                         SuccessOrExit(err);
144                     }
145
146                     //
147                     else
148                     {
149                         err =
150                             writer.PutString(ContextTag(tlvTagNum), Uint8::to_const_char(reader.GetValue()), reader.GetValueLen());
151                         SuccessOrExit(err);
152                     }
153                 }
154                 ASN1_EXIT_SEQUENCE;
155
156                 // Only one AttributeTypeAndValue allowed per RDN.
157                 err = reader.Next();
158                 if (err == ASN1_NO_ERROR)
159                 {
160                     ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
161                 }
162                 if (err != ASN1_END)
163                 {
164                     ExitNow();
165                 }
166             }
167             ASN1_EXIT_SET;
168         }
169     }
170     ASN1_EXIT_SEQUENCE;
171
172     err = writer.EndContainer(outerContainer);
173     SuccessOrExit(err);
174
175 exit:
176     return err;
177 }
178
179 static CHIP_ERROR ConvertValidity(ASN1Reader & reader, TLVWriter & writer)
180 {
181     CHIP_ERROR err;
182     ASN1UniversalTime asn1Time;
183     uint32_t chipEpochTime;
184
185     ASN1_PARSE_ENTER_SEQUENCE
186     {
187         ASN1_PARSE_TIME(asn1Time);
188
189         err = ASN1ToChipEpochTime(asn1Time, chipEpochTime);
190         SuccessOrExit(err);
191
192         err = writer.Put(ContextTag(kTag_NotBefore), chipEpochTime);
193         SuccessOrExit(err);
194
195         ASN1_PARSE_TIME(asn1Time);
196
197         err = ASN1ToChipEpochTime(asn1Time, chipEpochTime);
198         SuccessOrExit(err);
199
200         err = writer.Put(ContextTag(kTag_NotAfter), chipEpochTime);
201         SuccessOrExit(err);
202     }
203     ASN1_EXIT_SEQUENCE;
204
205 exit:
206     return err;
207 }
208
209 static CHIP_ERROR ConvertSubjectPublicKeyInfo(ASN1Reader & reader, TLVWriter & writer)
210 {
211     CHIP_ERROR err;
212     OID pubKeyAlgoOID, pubKeyCurveOID;
213
214     // subjectPublicKeyInfo SubjectPublicKeyInfo,
215     ASN1_PARSE_ENTER_SEQUENCE
216     {
217         // algorithm AlgorithmIdentifier,
218         // AlgorithmIdentifier ::= SEQUENCE
219         ASN1_PARSE_ENTER_SEQUENCE
220         {
221             // algorithm OBJECT IDENTIFIER,
222             ASN1_PARSE_OBJECT_ID(pubKeyAlgoOID);
223
224             // Verify that the algorithm type is supported.
225             VerifyOrExit(pubKeyAlgoOID == kOID_PubKeyAlgo_ECPublicKey, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
226
227             err = writer.Put(ContextTag(kTag_PublicKeyAlgorithm), GetOIDEnum(pubKeyAlgoOID));
228             SuccessOrExit(err);
229
230             // EcpkParameters ::= CHOICE {
231             //     ecParameters  ECParameters,
232             //     namedCurve    OBJECT IDENTIFIER,
233             //     implicitlyCA  NULL }
234             ASN1_PARSE_ANY;
235
236             // ecParameters and implicitlyCA not supported.
237             if (reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Sequence)
238             {
239                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
240             }
241             if (reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Null)
242             {
243                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
244             }
245
246             ASN1_VERIFY_TAG(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
247
248             ASN1_GET_OBJECT_ID(pubKeyCurveOID);
249
250             // Verify the curve name is recognized.
251             VerifyOrExit(GetOIDCategory(pubKeyCurveOID) == kOIDCategory_EllipticCurve, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
252
253             err = writer.Put(ContextTag(kTag_EllipticCurveIdentifier), GetOIDEnum(pubKeyCurveOID));
254             SuccessOrExit(err);
255         }
256         ASN1_EXIT_SEQUENCE;
257
258         // subjectPublicKey BIT STRING
259         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_BitString);
260
261         // Verify public key length.
262         VerifyOrExit(reader.GetValueLen() > 0, err = ASN1_ERROR_INVALID_ENCODING);
263
264         // The first byte is Unused Bit Count value, which should be zero.
265         VerifyOrExit(reader.GetValue()[0] == 0, err = ASN1_ERROR_INVALID_ENCODING);
266
267         // Copy the X9.62 encoded EC point into the CHIP certificate as a byte string.
268         // Skip the first Unused Bit Count byte.
269         err = writer.PutBytes(ContextTag(kTag_EllipticCurvePublicKey), reader.GetValue() + 1, reader.GetValueLen() - 1);
270         SuccessOrExit(err);
271     }
272     ASN1_EXIT_SEQUENCE;
273
274 exit:
275     return err;
276 }
277
278 static CHIP_ERROR ConvertExtension(ASN1Reader & reader, TLVWriter & writer)
279 {
280     CHIP_ERROR err;
281     TLVType outerContainer;
282     OID extensionOID;
283     bool critical = false;
284
285     // Extension ::= SEQUENCE
286     ASN1_ENTER_SEQUENCE
287     {
288         // extnID OBJECT IDENTIFIER,
289         ASN1_PARSE_OBJECT_ID(extensionOID);
290
291         VerifyOrExit(extensionOID != kOID_Unknown, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
292         VerifyOrExit(GetOIDCategory(extensionOID) == kOIDCategory_Extension, err = ASN1_ERROR_INVALID_ENCODING);
293
294         // critical BOOLEAN DEFAULT FALSE,
295         ASN1_PARSE_ANY;
296         if (reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Boolean)
297         {
298             ASN1_GET_BOOLEAN(critical);
299
300             VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
301
302             ASN1_PARSE_ANY;
303         }
304
305         // extnValue OCTET STRING
306         //           -- contains the DER encoding of an ASN.1 value
307         //           -- corresponding to the extension type identified
308         //           -- by extnID
309         ASN1_ENTER_ENCAPSULATED(kASN1TagClass_Universal, kASN1UniversalTag_OctetString)
310         {
311             if (extensionOID == kOID_Extension_AuthorityKeyIdentifier)
312             {
313                 // This extension MUST be marked as non-critical.
314                 VerifyOrExit(!critical, err = ASN1_ERROR_INVALID_ENCODING);
315
316                 // AuthorityKeyIdentifier ::= SEQUENCE
317                 ASN1_PARSE_ENTER_SEQUENCE
318                 {
319                     err = reader.Next();
320                     VerifyOrExit(err == ASN1_NO_ERROR, err = ASN1_ERROR_INVALID_ENCODING);
321
322                     // keyIdentifier [0] IMPLICIT KeyIdentifier,
323                     // KeyIdentifier ::= OCTET STRING
324                     VerifyOrExit(reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 0,
325                                  err = ASN1_ERROR_INVALID_ENCODING);
326
327                     VerifyOrExit(reader.IsConstructed() == false, err = ASN1_ERROR_INVALID_ENCODING);
328                     VerifyOrExit(reader.GetValueLen() == kKeyIdentifierLength, err = ASN1_ERROR_INVALID_ENCODING);
329
330                     err = writer.PutBytes(ContextTag(kTag_AuthorityKeyIdentifier), reader.GetValue(), reader.GetValueLen());
331                     SuccessOrExit(err);
332
333                     err = reader.Next();
334                     VerifyOrExit(err == ASN1_END, err = ASN1_ERROR_INVALID_ENCODING);
335                 }
336                 ASN1_EXIT_SEQUENCE;
337             }
338             else if (extensionOID == kOID_Extension_SubjectKeyIdentifier)
339             {
340                 // This extension MUST be marked as non-critical.
341                 VerifyOrExit(!critical, err = ASN1_ERROR_INVALID_ENCODING);
342
343                 // SubjectKeyIdentifier ::= KeyIdentifier
344                 // KeyIdentifier ::= OCTET STRING
345                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
346
347                 VerifyOrExit(reader.GetValueLen() == kKeyIdentifierLength, err = ASN1_ERROR_INVALID_ENCODING);
348
349                 err = writer.PutBytes(ContextTag(kTag_SubjectKeyIdentifier), reader.GetValue(), reader.GetValueLen());
350                 SuccessOrExit(err);
351             }
352             else if (extensionOID == kOID_Extension_KeyUsage)
353             {
354                 // This extension MUST be marked as critical.
355                 VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
356
357                 // KeyUsage ::= BIT STRING
358                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_BitString);
359
360                 uint32_t keyUsageBits;
361                 err = reader.GetBitString(keyUsageBits);
362                 SuccessOrExit(err);
363                 VerifyOrExit(keyUsageBits <= UINT16_MAX, err = ASN1_ERROR_INVALID_ENCODING);
364
365                 // Check that only supported flags are set.
366                 BitFlags<KeyUsageFlags> keyUsageFlags(static_cast<uint16_t>(keyUsageBits));
367                 VerifyOrExit(keyUsageFlags.HasOnly(
368                                  KeyUsageFlags::kDigitalSignature, KeyUsageFlags::kNonRepudiation, KeyUsageFlags::kKeyEncipherment,
369                                  KeyUsageFlags::kDataEncipherment, KeyUsageFlags::kKeyAgreement, KeyUsageFlags::kKeyCertSign,
370                                  KeyUsageFlags::kCRLSign, KeyUsageFlags::kEncipherOnly, KeyUsageFlags::kEncipherOnly),
371                              err = ASN1_ERROR_INVALID_ENCODING);
372
373                 err = writer.Put(ContextTag(kTag_KeyUsage), keyUsageBits);
374                 SuccessOrExit(err);
375             }
376             else if (extensionOID == kOID_Extension_BasicConstraints)
377             {
378                 // This extension MUST be marked as critical.
379                 VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
380
381                 // BasicConstraints ::= SEQUENCE
382                 ASN1_PARSE_ENTER_SEQUENCE
383                 {
384                     bool isCA                 = false;
385                     int64_t pathLenConstraint = -1;
386
387                     // cA BOOLEAN DEFAULT FALSE
388                     err = reader.Next();
389                     if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_Universal &&
390                         reader.GetTag() == kASN1UniversalTag_Boolean)
391                     {
392                         ASN1_GET_BOOLEAN(isCA);
393
394                         VerifyOrExit(isCA, err = ASN1_ERROR_INVALID_ENCODING);
395
396                         err = reader.Next();
397                     }
398
399                     // pathLenConstraint INTEGER (0..MAX) OPTIONAL
400                     if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_Universal &&
401                         reader.GetTag() == kASN1UniversalTag_Integer)
402                     {
403                         ASN1_GET_INTEGER(pathLenConstraint);
404
405                         VerifyOrExit(pathLenConstraint <= UINT8_MAX, err = ASN1_ERROR_INVALID_ENCODING);
406                         VerifyOrExit(pathLenConstraint >= 0, err = ASN1_ERROR_INVALID_ENCODING);
407
408                         // pathLenConstraint is present only when cA is TRUE
409                         VerifyOrExit(isCA, err = ASN1_ERROR_INVALID_ENCODING);
410                     }
411
412                     err = writer.StartContainer(ContextTag(kTag_BasicConstraints), kTLVType_Structure, outerContainer);
413                     SuccessOrExit(err);
414
415                     // Set also when cA is FALSE
416                     err = writer.PutBoolean(ContextTag(kTag_BasicConstraints_IsCA), isCA);
417                     SuccessOrExit(err);
418
419                     if (pathLenConstraint != -1)
420                     {
421                         err = writer.Put(ContextTag(kTag_BasicConstraints_PathLenConstraint),
422                                          static_cast<uint8_t>(pathLenConstraint));
423                         SuccessOrExit(err);
424                     }
425
426                     err = writer.EndContainer(outerContainer);
427                     SuccessOrExit(err);
428                 }
429                 ASN1_EXIT_SEQUENCE;
430             }
431             else if (extensionOID == kOID_Extension_ExtendedKeyUsage)
432             {
433                 // This extension MUST be marked as critical.
434                 VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
435
436                 err = writer.StartContainer(ContextTag(kTag_ExtendedKeyUsage), kTLVType_Array, outerContainer);
437                 SuccessOrExit(err);
438
439                 // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
440                 ASN1_PARSE_ENTER_SEQUENCE
441                 {
442                     while ((err = reader.Next()) == ASN1_NO_ERROR)
443                     {
444                         // KeyPurposeId ::= OBJECT IDENTIFIER
445                         OID keyPurposeOID;
446                         ASN1_GET_OBJECT_ID(keyPurposeOID);
447
448                         VerifyOrExit(keyPurposeOID != kOID_Unknown, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
449                         VerifyOrExit(GetOIDCategory(keyPurposeOID) == kOIDCategory_KeyPurpose, err = ASN1_ERROR_INVALID_ENCODING);
450
451                         err = writer.Put(AnonymousTag, GetOIDEnum(keyPurposeOID));
452                         SuccessOrExit(err);
453                     }
454                     if (err != ASN1_END)
455                     {
456                         SuccessOrExit(err);
457                     }
458                 }
459                 ASN1_EXIT_SEQUENCE;
460
461                 err = writer.EndContainer(outerContainer);
462                 SuccessOrExit(err);
463             }
464             else
465             {
466                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
467             }
468         }
469         ASN1_EXIT_ENCAPSULATED;
470     }
471     ASN1_EXIT_SEQUENCE;
472
473 exit:
474     return err;
475 }
476
477 static CHIP_ERROR ConvertExtensions(ASN1Reader & reader, TLVWriter & writer)
478 {
479     CHIP_ERROR err;
480
481     // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
482     ASN1_PARSE_ENTER_SEQUENCE
483     {
484         while ((err = reader.Next()) == ASN1_NO_ERROR)
485         {
486             err = ConvertExtension(reader, writer);
487             SuccessOrExit(err);
488         }
489
490         if (err != ASN1_END)
491         {
492             SuccessOrExit(err);
493         }
494     }
495     ASN1_EXIT_SEQUENCE;
496
497 exit:
498     return err;
499 }
500
501 static CHIP_ERROR ConvertCertificate(ASN1Reader & reader, TLVWriter & writer)
502 {
503     CHIP_ERROR err;
504     int64_t version;
505     OID sigAlgoOID;
506     TLVType containerType;
507
508     err = writer.StartContainer(ProfileTag(kProtocol_OpCredentials, kTag_ChipCertificate), kTLVType_Structure, containerType);
509     SuccessOrExit(err);
510
511     // Certificate ::= SEQUENCE
512     ASN1_PARSE_ENTER_SEQUENCE
513     {
514         // tbsCertificate TBSCertificate,
515         // TBSCertificate ::= SEQUENCE
516         ASN1_PARSE_ENTER_SEQUENCE
517         {
518             // version [0] EXPLICIT Version DEFAULT v1
519             ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
520             {
521                 // Version ::= INTEGER { v1(0), v2(1), v3(2) }
522                 ASN1_PARSE_INTEGER(version);
523
524                 // Verify that the X.509 certificate version is v3
525                 VerifyOrExit(version == 2, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
526             }
527             ASN1_EXIT_CONSTRUCTED;
528
529             // serialNumber CertificateSerialNumber
530             // CertificateSerialNumber ::= INTEGER
531             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
532             err = writer.PutBytes(ContextTag(kTag_SerialNumber), reader.GetValue(), reader.GetValueLen());
533             SuccessOrExit(err);
534
535             // signature AlgorithmIdentifier
536             // AlgorithmIdentifier ::= SEQUENCE
537             ASN1_PARSE_ENTER_SEQUENCE
538             {
539                 // algorithm OBJECT IDENTIFIER,
540                 ASN1_PARSE_OBJECT_ID(sigAlgoOID);
541
542                 VerifyOrExit(sigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
543
544                 err = writer.Put(ContextTag(kTag_SignatureAlgorithm), GetOIDEnum(sigAlgoOID));
545                 SuccessOrExit(err);
546             }
547             ASN1_EXIT_SEQUENCE;
548
549             // issuer Name
550             err = ConvertDistinguishedName(reader, writer, ContextTag(kTag_Issuer));
551             SuccessOrExit(err);
552
553             // validity Validity,
554             err = ConvertValidity(reader, writer);
555             SuccessOrExit(err);
556
557             // subject Name,
558             err = ConvertDistinguishedName(reader, writer, ContextTag(kTag_Subject));
559             SuccessOrExit(err);
560
561             err = ConvertSubjectPublicKeyInfo(reader, writer);
562             SuccessOrExit(err);
563
564             err = reader.Next();
565
566             // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
567             // Not supported.
568             if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 1)
569             {
570                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
571             }
572
573             // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
574             // Not supported.
575             if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 2)
576             {
577                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
578             }
579
580             // extensions [3] EXPLICIT Extensions OPTIONAL
581             if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 3)
582             {
583                 ASN1_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
584                 {
585                     err = ConvertExtensions(reader, writer);
586                     SuccessOrExit(err);
587                 }
588                 ASN1_EXIT_CONSTRUCTED;
589
590                 err = reader.Next();
591             }
592
593             if (err != ASN1_END)
594             {
595                 ExitNow();
596             }
597         }
598         ASN1_EXIT_SEQUENCE;
599
600         // signatureAlgorithm AlgorithmIdentifier
601         // AlgorithmIdentifier ::= SEQUENCE
602         ASN1_PARSE_ENTER_SEQUENCE
603         {
604             OID localSigAlgoOID;
605
606             // algorithm OBJECT IDENTIFIER,
607             ASN1_PARSE_OBJECT_ID(localSigAlgoOID);
608
609             // Verify that the signatureAlgorithm is the same as the "signature" field in TBSCertificate.
610             VerifyOrExit(localSigAlgoOID == sigAlgoOID, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
611         }
612         ASN1_EXIT_SEQUENCE;
613
614         // signatureValue BIT STRING
615         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_BitString);
616
617         // Per RFC3279, the ECDSA signature value is encoded in DER encapsulated in the signatureValue BIT STRING.
618         ASN1_ENTER_ENCAPSULATED(kASN1TagClass_Universal, kASN1UniversalTag_BitString)
619         {
620             TLVType outerContainer;
621
622             err = writer.StartContainer(ContextTag(kTag_ECDSASignature), kTLVType_Structure, outerContainer);
623             SuccessOrExit(err);
624
625             // Ecdsa-Sig-Value ::= SEQUENCE
626             ASN1_PARSE_ENTER_SEQUENCE
627             {
628                 // r INTEGER
629                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
630                 err = writer.PutBytes(ContextTag(kTag_ECDSASignature_r), reader.GetValue(), reader.GetValueLen());
631                 SuccessOrExit(err);
632
633                 // s INTEGER
634                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
635                 err = writer.PutBytes(ContextTag(kTag_ECDSASignature_s), reader.GetValue(), reader.GetValueLen());
636                 SuccessOrExit(err);
637             }
638             ASN1_EXIT_SEQUENCE;
639
640             err = writer.EndContainer(outerContainer);
641             SuccessOrExit(err);
642         }
643         ASN1_EXIT_ENCAPSULATED;
644     }
645     ASN1_EXIT_SEQUENCE;
646
647     err = writer.EndContainer(containerType);
648     SuccessOrExit(err);
649
650 exit:
651     return err;
652 }
653
654 DLL_EXPORT CHIP_ERROR ConvertX509CertToChipCert(const uint8_t * x509Cert, uint32_t x509CertLen, uint8_t * chipCertBuf,
655                                                 uint32_t chipCertBufSize, uint32_t & chipCertLen)
656 {
657     CHIP_ERROR err;
658     ASN1Reader reader;
659     TLVWriter writer;
660
661     reader.Init(x509Cert, x509CertLen);
662
663     writer.Init(chipCertBuf, chipCertBufSize);
664
665     err = ConvertCertificate(reader, writer);
666     SuccessOrExit(err);
667
668     err = writer.Finalize();
669     SuccessOrExit(err);
670
671     chipCertLen = writer.GetLengthWritten();
672
673 exit:
674     return err;
675 }
676
677 } // namespace Credentials
678 } // namespace chip