Fix for x86_64 build fail
[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(Protocols::OpCredentials::Id.ToTLVProfileId(), kTag_ChipCertificate), kTLVType_Structure,
509                                 containerType);
510     SuccessOrExit(err);
511
512     // Certificate ::= SEQUENCE
513     ASN1_PARSE_ENTER_SEQUENCE
514     {
515         // tbsCertificate TBSCertificate,
516         // TBSCertificate ::= SEQUENCE
517         ASN1_PARSE_ENTER_SEQUENCE
518         {
519             // version [0] EXPLICIT Version DEFAULT v1
520             ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
521             {
522                 // Version ::= INTEGER { v1(0), v2(1), v3(2) }
523                 ASN1_PARSE_INTEGER(version);
524
525                 // Verify that the X.509 certificate version is v3
526                 VerifyOrExit(version == 2, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
527             }
528             ASN1_EXIT_CONSTRUCTED;
529
530             // serialNumber CertificateSerialNumber
531             // CertificateSerialNumber ::= INTEGER
532             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
533             err = writer.PutBytes(ContextTag(kTag_SerialNumber), reader.GetValue(), reader.GetValueLen());
534             SuccessOrExit(err);
535
536             // signature AlgorithmIdentifier
537             // AlgorithmIdentifier ::= SEQUENCE
538             ASN1_PARSE_ENTER_SEQUENCE
539             {
540                 // algorithm OBJECT IDENTIFIER,
541                 ASN1_PARSE_OBJECT_ID(sigAlgoOID);
542
543                 VerifyOrExit(sigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
544
545                 err = writer.Put(ContextTag(kTag_SignatureAlgorithm), GetOIDEnum(sigAlgoOID));
546                 SuccessOrExit(err);
547             }
548             ASN1_EXIT_SEQUENCE;
549
550             // issuer Name
551             err = ConvertDistinguishedName(reader, writer, ContextTag(kTag_Issuer));
552             SuccessOrExit(err);
553
554             // validity Validity,
555             err = ConvertValidity(reader, writer);
556             SuccessOrExit(err);
557
558             // subject Name,
559             err = ConvertDistinguishedName(reader, writer, ContextTag(kTag_Subject));
560             SuccessOrExit(err);
561
562             err = ConvertSubjectPublicKeyInfo(reader, writer);
563             SuccessOrExit(err);
564
565             err = reader.Next();
566
567             // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
568             // Not supported.
569             if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 1)
570             {
571                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
572             }
573
574             // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
575             // Not supported.
576             if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 2)
577             {
578                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
579             }
580
581             // extensions [3] EXPLICIT Extensions OPTIONAL
582             if (err == ASN1_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 3)
583             {
584                 ASN1_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
585                 {
586                     err = ConvertExtensions(reader, writer);
587                     SuccessOrExit(err);
588                 }
589                 ASN1_EXIT_CONSTRUCTED;
590
591                 err = reader.Next();
592             }
593
594             if (err != ASN1_END)
595             {
596                 ExitNow();
597             }
598         }
599         ASN1_EXIT_SEQUENCE;
600
601         // signatureAlgorithm AlgorithmIdentifier
602         // AlgorithmIdentifier ::= SEQUENCE
603         ASN1_PARSE_ENTER_SEQUENCE
604         {
605             OID localSigAlgoOID;
606
607             // algorithm OBJECT IDENTIFIER,
608             ASN1_PARSE_OBJECT_ID(localSigAlgoOID);
609
610             // Verify that the signatureAlgorithm is the same as the "signature" field in TBSCertificate.
611             VerifyOrExit(localSigAlgoOID == sigAlgoOID, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
612         }
613         ASN1_EXIT_SEQUENCE;
614
615         // signatureValue BIT STRING
616         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_BitString);
617
618         // Per RFC3279, the ECDSA signature value is encoded in DER encapsulated in the signatureValue BIT STRING.
619         ASN1_ENTER_ENCAPSULATED(kASN1TagClass_Universal, kASN1UniversalTag_BitString)
620         {
621             TLVType outerContainer;
622
623             err = writer.StartContainer(ContextTag(kTag_ECDSASignature), kTLVType_Structure, outerContainer);
624             SuccessOrExit(err);
625
626             // Ecdsa-Sig-Value ::= SEQUENCE
627             ASN1_PARSE_ENTER_SEQUENCE
628             {
629                 // r INTEGER
630                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
631                 err = writer.PutBytes(ContextTag(kTag_ECDSASignature_r), reader.GetValue(), reader.GetValueLen());
632                 SuccessOrExit(err);
633
634                 // s INTEGER
635                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
636                 err = writer.PutBytes(ContextTag(kTag_ECDSASignature_s), reader.GetValue(), reader.GetValueLen());
637                 SuccessOrExit(err);
638             }
639             ASN1_EXIT_SEQUENCE;
640
641             err = writer.EndContainer(outerContainer);
642             SuccessOrExit(err);
643         }
644         ASN1_EXIT_ENCAPSULATED;
645     }
646     ASN1_EXIT_SEQUENCE;
647
648     err = writer.EndContainer(containerType);
649     SuccessOrExit(err);
650
651 exit:
652     return err;
653 }
654
655 DLL_EXPORT CHIP_ERROR ConvertX509CertToChipCert(const uint8_t * x509Cert, uint32_t x509CertLen, uint8_t * chipCertBuf,
656                                                 uint32_t chipCertBufSize, uint32_t & chipCertLen)
657 {
658     CHIP_ERROR err;
659     ASN1Reader reader;
660     TLVWriter writer;
661
662     reader.Init(x509Cert, x509CertLen);
663
664     writer.Init(chipCertBuf, chipCertBufSize);
665
666     err = ConvertCertificate(reader, writer);
667     SuccessOrExit(err);
668
669     err = writer.Finalize();
670     SuccessOrExit(err);
671
672     chipCertLen = writer.GetLengthWritten();
673
674 exit:
675     return err;
676 }
677
678 } // namespace Credentials
679 } // namespace chip