xref: /aosp_15_r20/external/curl/lib/vtls/x509asn1.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #if defined(USE_GNUTLS) || defined(USE_WOLFSSL) ||      \
28*6236dae4SAndroid Build Coastguard Worker   defined(USE_SCHANNEL) || defined(USE_SECTRANSP) ||    \
29*6236dae4SAndroid Build Coastguard Worker   defined(USE_MBEDTLS)
30*6236dae4SAndroid Build Coastguard Worker 
31*6236dae4SAndroid Build Coastguard Worker #if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
32*6236dae4SAndroid Build Coastguard Worker #define WANT_PARSEX509 /* uses Curl_parseX509() */
33*6236dae4SAndroid Build Coastguard Worker #endif
34*6236dae4SAndroid Build Coastguard Worker 
35*6236dae4SAndroid Build Coastguard Worker #if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
36*6236dae4SAndroid Build Coastguard Worker   defined(USE_MBEDTLS)
37*6236dae4SAndroid Build Coastguard Worker #define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
38*6236dae4SAndroid Build Coastguard Worker #define WANT_PARSEX509 /* ... uses Curl_parseX509() */
39*6236dae4SAndroid Build Coastguard Worker #endif
40*6236dae4SAndroid Build Coastguard Worker 
41*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
42*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
43*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
44*6236dae4SAndroid Build Coastguard Worker #include "curl_ctype.h"
45*6236dae4SAndroid Build Coastguard Worker #include "hostcheck.h"
46*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
47*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls_int.h"
48*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
49*6236dae4SAndroid Build Coastguard Worker #include "inet_pton.h"
50*6236dae4SAndroid Build Coastguard Worker #include "curl_base64.h"
51*6236dae4SAndroid Build Coastguard Worker #include "x509asn1.h"
52*6236dae4SAndroid Build Coastguard Worker #include "dynbuf.h"
53*6236dae4SAndroid Build Coastguard Worker 
54*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
55*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
56*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
57*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
58*6236dae4SAndroid Build Coastguard Worker 
59*6236dae4SAndroid Build Coastguard Worker /*
60*6236dae4SAndroid Build Coastguard Worker  * Constants.
61*6236dae4SAndroid Build Coastguard Worker  */
62*6236dae4SAndroid Build Coastguard Worker 
63*6236dae4SAndroid Build Coastguard Worker /* Largest supported ASN.1 structure. */
64*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_MAX                   ((size_t) 0x40000)      /* 256K */
65*6236dae4SAndroid Build Coastguard Worker 
66*6236dae4SAndroid Build Coastguard Worker /* ASN.1 classes. */
67*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_UNIVERSAL             0
68*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_APPLICATION           1
69*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_CONTEXT_SPECIFIC      2
70*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_PRIVATE               3
71*6236dae4SAndroid Build Coastguard Worker 
72*6236dae4SAndroid Build Coastguard Worker /* ASN.1 types. */
73*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_BOOLEAN               1
74*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_INTEGER               2
75*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_BIT_STRING            3
76*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_OCTET_STRING          4
77*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_NULL                  5
78*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_OBJECT_IDENTIFIER     6
79*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_OBJECT_DESCRIPTOR     7
80*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_INSTANCE_OF           8
81*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_REAL                  9
82*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_ENUMERATED            10
83*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_EMBEDDED              11
84*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_UTF8_STRING           12
85*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_RELATIVE_OID          13
86*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_SEQUENCE              16
87*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_SET                   17
88*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_NUMERIC_STRING        18
89*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_PRINTABLE_STRING      19
90*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_TELETEX_STRING        20
91*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_VIDEOTEX_STRING       21
92*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_IA5_STRING            22
93*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_UTC_TIME              23
94*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_GENERALIZED_TIME      24
95*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_GRAPHIC_STRING        25
96*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_VISIBLE_STRING        26
97*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_GENERAL_STRING        27
98*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_UNIVERSAL_STRING      28
99*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_CHARACTER_STRING      29
100*6236dae4SAndroid Build Coastguard Worker #define CURL_ASN1_BMP_STRING            30
101*6236dae4SAndroid Build Coastguard Worker 
102*6236dae4SAndroid Build Coastguard Worker 
103*6236dae4SAndroid Build Coastguard Worker #ifdef WANT_EXTRACT_CERTINFO
104*6236dae4SAndroid Build Coastguard Worker /* ASN.1 OID table entry. */
105*6236dae4SAndroid Build Coastguard Worker struct Curl_OID {
106*6236dae4SAndroid Build Coastguard Worker   const char *numoid;  /* Dotted-numeric OID. */
107*6236dae4SAndroid Build Coastguard Worker   const char *textoid; /* OID name. */
108*6236dae4SAndroid Build Coastguard Worker };
109*6236dae4SAndroid Build Coastguard Worker 
110*6236dae4SAndroid Build Coastguard Worker /* ASN.1 OIDs. */
111*6236dae4SAndroid Build Coastguard Worker static const struct Curl_OID OIDtable[] = {
112*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10040.4.1",        "dsa" },
113*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10040.4.3",        "dsa-with-sha1" },
114*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10045.2.1",        "ecPublicKey" },
115*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10045.3.0.1",      "c2pnb163v1" },
116*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10045.4.1",        "ecdsa-with-SHA1" },
117*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10045.4.3.1",      "ecdsa-with-SHA224" },
118*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10045.4.3.2",      "ecdsa-with-SHA256" },
119*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10045.4.3.3",      "ecdsa-with-SHA384" },
120*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10045.4.3.4",      "ecdsa-with-SHA512" },
121*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.10046.2.1",        "dhpublicnumber" },
122*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.1",     "rsaEncryption" },
123*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.2",     "md2WithRSAEncryption" },
124*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.4",     "md5WithRSAEncryption" },
125*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.5",     "sha1WithRSAEncryption" },
126*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.10",    "RSASSA-PSS" },
127*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.14",    "sha224WithRSAEncryption" },
128*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.11",    "sha256WithRSAEncryption" },
129*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.12",    "sha384WithRSAEncryption" },
130*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.1.13",    "sha512WithRSAEncryption" },
131*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.2.2",       "md2" },
132*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.2.5",       "md5" },
133*6236dae4SAndroid Build Coastguard Worker   { "1.3.14.3.2.26",            "sha1" },
134*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.3",                  "CN" },
135*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.4",                  "SN" },
136*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.5",                  "serialNumber" },
137*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.6",                  "C" },
138*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.7",                  "L" },
139*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.8",                  "ST" },
140*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.9",                  "streetAddress" },
141*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.10",                 "O" },
142*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.11",                 "OU" },
143*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.12",                 "title" },
144*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.13",                 "description" },
145*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.17",                 "postalCode" },
146*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.41",                 "name" },
147*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.42",                 "givenName" },
148*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.43",                 "initials" },
149*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.44",                 "generationQualifier" },
150*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.45",                 "X500UniqueIdentifier" },
151*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.46",                 "dnQualifier" },
152*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.65",                 "pseudonym" },
153*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.9.1",     "emailAddress" },
154*6236dae4SAndroid Build Coastguard Worker   { "2.5.4.72",                 "role" },
155*6236dae4SAndroid Build Coastguard Worker   { "2.5.29.17",                "subjectAltName" },
156*6236dae4SAndroid Build Coastguard Worker   { "2.5.29.18",                "issuerAltName" },
157*6236dae4SAndroid Build Coastguard Worker   { "2.5.29.19",                "basicConstraints" },
158*6236dae4SAndroid Build Coastguard Worker   { "2.16.840.1.101.3.4.2.4",   "sha224" },
159*6236dae4SAndroid Build Coastguard Worker   { "2.16.840.1.101.3.4.2.1",   "sha256" },
160*6236dae4SAndroid Build Coastguard Worker   { "2.16.840.1.101.3.4.2.2",   "sha384" },
161*6236dae4SAndroid Build Coastguard Worker   { "2.16.840.1.101.3.4.2.3",   "sha512" },
162*6236dae4SAndroid Build Coastguard Worker   { "1.2.840.113549.1.9.2",     "unstructuredName" },
163*6236dae4SAndroid Build Coastguard Worker   { (const char *) NULL,        (const char *) NULL }
164*6236dae4SAndroid Build Coastguard Worker };
165*6236dae4SAndroid Build Coastguard Worker 
166*6236dae4SAndroid Build Coastguard Worker #endif /* WANT_EXTRACT_CERTINFO */
167*6236dae4SAndroid Build Coastguard Worker 
168*6236dae4SAndroid Build Coastguard Worker /*
169*6236dae4SAndroid Build Coastguard Worker  * Lightweight ASN.1 parser.
170*6236dae4SAndroid Build Coastguard Worker  * In particular, it does not check for syntactic/lexical errors.
171*6236dae4SAndroid Build Coastguard Worker  * It is intended to support certificate information gathering for SSL backends
172*6236dae4SAndroid Build Coastguard Worker  * that offer a mean to get certificates as a whole, but do not supply
173*6236dae4SAndroid Build Coastguard Worker  * entry points to get particular certificate sub-fields.
174*6236dae4SAndroid Build Coastguard Worker  * Please note there is no pretension here to rewrite a full SSL library.
175*6236dae4SAndroid Build Coastguard Worker  */
176*6236dae4SAndroid Build Coastguard Worker 
177*6236dae4SAndroid Build Coastguard Worker static const char *getASN1Element(struct Curl_asn1Element *elem,
178*6236dae4SAndroid Build Coastguard Worker                                   const char *beg, const char *end)
179*6236dae4SAndroid Build Coastguard Worker   WARN_UNUSED_RESULT;
180*6236dae4SAndroid Build Coastguard Worker 
getASN1Element(struct Curl_asn1Element * elem,const char * beg,const char * end)181*6236dae4SAndroid Build Coastguard Worker static const char *getASN1Element(struct Curl_asn1Element *elem,
182*6236dae4SAndroid Build Coastguard Worker                                   const char *beg, const char *end)
183*6236dae4SAndroid Build Coastguard Worker {
184*6236dae4SAndroid Build Coastguard Worker   unsigned char b;
185*6236dae4SAndroid Build Coastguard Worker   size_t len;
186*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element lelem;
187*6236dae4SAndroid Build Coastguard Worker 
188*6236dae4SAndroid Build Coastguard Worker   /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
189*6236dae4SAndroid Build Coastguard Worker      ending at `end'.
190*6236dae4SAndroid Build Coastguard Worker      Returns a pointer in source string after the parsed element, or NULL
191*6236dae4SAndroid Build Coastguard Worker      if an error occurs. */
192*6236dae4SAndroid Build Coastguard Worker   if(!beg || !end || beg >= end || !*beg ||
193*6236dae4SAndroid Build Coastguard Worker      (size_t)(end - beg) > CURL_ASN1_MAX)
194*6236dae4SAndroid Build Coastguard Worker     return NULL;
195*6236dae4SAndroid Build Coastguard Worker 
196*6236dae4SAndroid Build Coastguard Worker   /* Process header byte. */
197*6236dae4SAndroid Build Coastguard Worker   elem->header = beg;
198*6236dae4SAndroid Build Coastguard Worker   b = (unsigned char) *beg++;
199*6236dae4SAndroid Build Coastguard Worker   elem->constructed = (b & 0x20) != 0;
200*6236dae4SAndroid Build Coastguard Worker   elem->class = (b >> 6) & 3;
201*6236dae4SAndroid Build Coastguard Worker   b &= 0x1F;
202*6236dae4SAndroid Build Coastguard Worker   if(b == 0x1F)
203*6236dae4SAndroid Build Coastguard Worker     return NULL; /* Long tag values not supported here. */
204*6236dae4SAndroid Build Coastguard Worker   elem->tag = b;
205*6236dae4SAndroid Build Coastguard Worker 
206*6236dae4SAndroid Build Coastguard Worker   /* Process length. */
207*6236dae4SAndroid Build Coastguard Worker   if(beg >= end)
208*6236dae4SAndroid Build Coastguard Worker     return NULL;
209*6236dae4SAndroid Build Coastguard Worker   b = (unsigned char) *beg++;
210*6236dae4SAndroid Build Coastguard Worker   if(!(b & 0x80))
211*6236dae4SAndroid Build Coastguard Worker     len = b;
212*6236dae4SAndroid Build Coastguard Worker   else if(!(b &= 0x7F)) {
213*6236dae4SAndroid Build Coastguard Worker     /* Unspecified length. Since we have all the data, we can determine the
214*6236dae4SAndroid Build Coastguard Worker        effective length by skipping element until an end element is found. */
215*6236dae4SAndroid Build Coastguard Worker     if(!elem->constructed)
216*6236dae4SAndroid Build Coastguard Worker       return NULL;
217*6236dae4SAndroid Build Coastguard Worker     elem->beg = beg;
218*6236dae4SAndroid Build Coastguard Worker     while(beg < end && *beg) {
219*6236dae4SAndroid Build Coastguard Worker       beg = getASN1Element(&lelem, beg, end);
220*6236dae4SAndroid Build Coastguard Worker       if(!beg)
221*6236dae4SAndroid Build Coastguard Worker         return NULL;
222*6236dae4SAndroid Build Coastguard Worker     }
223*6236dae4SAndroid Build Coastguard Worker     if(beg >= end)
224*6236dae4SAndroid Build Coastguard Worker       return NULL;
225*6236dae4SAndroid Build Coastguard Worker     elem->end = beg;
226*6236dae4SAndroid Build Coastguard Worker     return beg + 1;
227*6236dae4SAndroid Build Coastguard Worker   }
228*6236dae4SAndroid Build Coastguard Worker   else if((unsigned)b > (size_t)(end - beg))
229*6236dae4SAndroid Build Coastguard Worker     return NULL; /* Does not fit in source. */
230*6236dae4SAndroid Build Coastguard Worker   else {
231*6236dae4SAndroid Build Coastguard Worker     /* Get long length. */
232*6236dae4SAndroid Build Coastguard Worker     len = 0;
233*6236dae4SAndroid Build Coastguard Worker     do {
234*6236dae4SAndroid Build Coastguard Worker       if(len & 0xFF000000L)
235*6236dae4SAndroid Build Coastguard Worker         return NULL;  /* Lengths > 32 bits are not supported. */
236*6236dae4SAndroid Build Coastguard Worker       len = (len << 8) | (unsigned char) *beg++;
237*6236dae4SAndroid Build Coastguard Worker     } while(--b);
238*6236dae4SAndroid Build Coastguard Worker   }
239*6236dae4SAndroid Build Coastguard Worker   if(len > (size_t)(end - beg))
240*6236dae4SAndroid Build Coastguard Worker     return NULL;  /* Element data does not fit in source. */
241*6236dae4SAndroid Build Coastguard Worker   elem->beg = beg;
242*6236dae4SAndroid Build Coastguard Worker   elem->end = beg + len;
243*6236dae4SAndroid Build Coastguard Worker   return elem->end;
244*6236dae4SAndroid Build Coastguard Worker }
245*6236dae4SAndroid Build Coastguard Worker 
246*6236dae4SAndroid Build Coastguard Worker #ifdef WANT_EXTRACT_CERTINFO
247*6236dae4SAndroid Build Coastguard Worker 
248*6236dae4SAndroid Build Coastguard Worker /*
249*6236dae4SAndroid Build Coastguard Worker  * Search the null terminated OID or OID identifier in local table.
250*6236dae4SAndroid Build Coastguard Worker  * Return the table entry pointer or NULL if not found.
251*6236dae4SAndroid Build Coastguard Worker  */
searchOID(const char * oid)252*6236dae4SAndroid Build Coastguard Worker static const struct Curl_OID *searchOID(const char *oid)
253*6236dae4SAndroid Build Coastguard Worker {
254*6236dae4SAndroid Build Coastguard Worker   const struct Curl_OID *op;
255*6236dae4SAndroid Build Coastguard Worker   for(op = OIDtable; op->numoid; op++)
256*6236dae4SAndroid Build Coastguard Worker     if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
257*6236dae4SAndroid Build Coastguard Worker       return op;
258*6236dae4SAndroid Build Coastguard Worker 
259*6236dae4SAndroid Build Coastguard Worker   return NULL;
260*6236dae4SAndroid Build Coastguard Worker }
261*6236dae4SAndroid Build Coastguard Worker 
262*6236dae4SAndroid Build Coastguard Worker /*
263*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 Boolean value into its string representation.
264*6236dae4SAndroid Build Coastguard Worker  *
265*6236dae4SAndroid Build Coastguard Worker  * Return error code.
266*6236dae4SAndroid Build Coastguard Worker  */
267*6236dae4SAndroid Build Coastguard Worker 
bool2str(struct dynbuf * store,const char * beg,const char * end)268*6236dae4SAndroid Build Coastguard Worker static CURLcode bool2str(struct dynbuf *store,
269*6236dae4SAndroid Build Coastguard Worker                          const char *beg, const char *end)
270*6236dae4SAndroid Build Coastguard Worker {
271*6236dae4SAndroid Build Coastguard Worker   if(end - beg != 1)
272*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
273*6236dae4SAndroid Build Coastguard Worker   return Curl_dyn_add(store, *beg ? "TRUE": "FALSE");
274*6236dae4SAndroid Build Coastguard Worker }
275*6236dae4SAndroid Build Coastguard Worker 
276*6236dae4SAndroid Build Coastguard Worker /*
277*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 octet string to a printable string.
278*6236dae4SAndroid Build Coastguard Worker  *
279*6236dae4SAndroid Build Coastguard Worker  * Return error code.
280*6236dae4SAndroid Build Coastguard Worker  */
octet2str(struct dynbuf * store,const char * beg,const char * end)281*6236dae4SAndroid Build Coastguard Worker static CURLcode octet2str(struct dynbuf *store,
282*6236dae4SAndroid Build Coastguard Worker                           const char *beg, const char *end)
283*6236dae4SAndroid Build Coastguard Worker {
284*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
285*6236dae4SAndroid Build Coastguard Worker 
286*6236dae4SAndroid Build Coastguard Worker   while(!result && beg < end)
287*6236dae4SAndroid Build Coastguard Worker     result = Curl_dyn_addf(store, "%02x:", (unsigned char) *beg++);
288*6236dae4SAndroid Build Coastguard Worker 
289*6236dae4SAndroid Build Coastguard Worker   return result;
290*6236dae4SAndroid Build Coastguard Worker }
291*6236dae4SAndroid Build Coastguard Worker 
bit2str(struct dynbuf * store,const char * beg,const char * end)292*6236dae4SAndroid Build Coastguard Worker static CURLcode bit2str(struct dynbuf *store,
293*6236dae4SAndroid Build Coastguard Worker                         const char *beg, const char *end)
294*6236dae4SAndroid Build Coastguard Worker {
295*6236dae4SAndroid Build Coastguard Worker   /* Convert an ASN.1 bit string to a printable string. */
296*6236dae4SAndroid Build Coastguard Worker 
297*6236dae4SAndroid Build Coastguard Worker   if(++beg > end)
298*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
299*6236dae4SAndroid Build Coastguard Worker   return octet2str(store, beg, end);
300*6236dae4SAndroid Build Coastguard Worker }
301*6236dae4SAndroid Build Coastguard Worker 
302*6236dae4SAndroid Build Coastguard Worker /*
303*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 integer value into its string representation.
304*6236dae4SAndroid Build Coastguard Worker  *
305*6236dae4SAndroid Build Coastguard Worker  * Returns error.
306*6236dae4SAndroid Build Coastguard Worker  */
int2str(struct dynbuf * store,const char * beg,const char * end)307*6236dae4SAndroid Build Coastguard Worker static CURLcode int2str(struct dynbuf *store,
308*6236dae4SAndroid Build Coastguard Worker                         const char *beg, const char *end)
309*6236dae4SAndroid Build Coastguard Worker {
310*6236dae4SAndroid Build Coastguard Worker   unsigned int val = 0;
311*6236dae4SAndroid Build Coastguard Worker   size_t n = end - beg;
312*6236dae4SAndroid Build Coastguard Worker 
313*6236dae4SAndroid Build Coastguard Worker   if(!n)
314*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
315*6236dae4SAndroid Build Coastguard Worker 
316*6236dae4SAndroid Build Coastguard Worker   if(n > 4)
317*6236dae4SAndroid Build Coastguard Worker     return octet2str(store, beg, end);
318*6236dae4SAndroid Build Coastguard Worker 
319*6236dae4SAndroid Build Coastguard Worker   /* Represent integers <= 32-bit as a single value. */
320*6236dae4SAndroid Build Coastguard Worker   if(*beg & 0x80)
321*6236dae4SAndroid Build Coastguard Worker     val = ~val;
322*6236dae4SAndroid Build Coastguard Worker 
323*6236dae4SAndroid Build Coastguard Worker   do
324*6236dae4SAndroid Build Coastguard Worker     val = (val << 8) | *(const unsigned char *) beg++;
325*6236dae4SAndroid Build Coastguard Worker   while(beg < end);
326*6236dae4SAndroid Build Coastguard Worker   return Curl_dyn_addf(store, "%s%x", val >= 10 ? "0x" : "", val);
327*6236dae4SAndroid Build Coastguard Worker }
328*6236dae4SAndroid Build Coastguard Worker 
329*6236dae4SAndroid Build Coastguard Worker /*
330*6236dae4SAndroid Build Coastguard Worker  * Convert from an ASN.1 typed string to UTF8.
331*6236dae4SAndroid Build Coastguard Worker  *
332*6236dae4SAndroid Build Coastguard Worker  * The result is stored in a dynbuf that is inited by the user of this
333*6236dae4SAndroid Build Coastguard Worker  * function.
334*6236dae4SAndroid Build Coastguard Worker  *
335*6236dae4SAndroid Build Coastguard Worker  * Returns error.
336*6236dae4SAndroid Build Coastguard Worker  */
337*6236dae4SAndroid Build Coastguard Worker static CURLcode
utf8asn1str(struct dynbuf * to,int type,const char * from,const char * end)338*6236dae4SAndroid Build Coastguard Worker utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
339*6236dae4SAndroid Build Coastguard Worker {
340*6236dae4SAndroid Build Coastguard Worker   size_t inlength = end - from;
341*6236dae4SAndroid Build Coastguard Worker   int size = 1;
342*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
343*6236dae4SAndroid Build Coastguard Worker 
344*6236dae4SAndroid Build Coastguard Worker   switch(type) {
345*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_BMP_STRING:
346*6236dae4SAndroid Build Coastguard Worker     size = 2;
347*6236dae4SAndroid Build Coastguard Worker     break;
348*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_UNIVERSAL_STRING:
349*6236dae4SAndroid Build Coastguard Worker     size = 4;
350*6236dae4SAndroid Build Coastguard Worker     break;
351*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_NUMERIC_STRING:
352*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_PRINTABLE_STRING:
353*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_TELETEX_STRING:
354*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_IA5_STRING:
355*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_VISIBLE_STRING:
356*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_UTF8_STRING:
357*6236dae4SAndroid Build Coastguard Worker     break;
358*6236dae4SAndroid Build Coastguard Worker   default:
359*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;  /* Conversion not supported. */
360*6236dae4SAndroid Build Coastguard Worker   }
361*6236dae4SAndroid Build Coastguard Worker 
362*6236dae4SAndroid Build Coastguard Worker   if(inlength % size)
363*6236dae4SAndroid Build Coastguard Worker     /* Length inconsistent with character size. */
364*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
365*6236dae4SAndroid Build Coastguard Worker 
366*6236dae4SAndroid Build Coastguard Worker   if(type == CURL_ASN1_UTF8_STRING) {
367*6236dae4SAndroid Build Coastguard Worker     /* Just copy. */
368*6236dae4SAndroid Build Coastguard Worker     if(inlength)
369*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(to, from, inlength);
370*6236dae4SAndroid Build Coastguard Worker   }
371*6236dae4SAndroid Build Coastguard Worker   else {
372*6236dae4SAndroid Build Coastguard Worker     while(!result && (from < end)) {
373*6236dae4SAndroid Build Coastguard Worker       char buf[4]; /* decode buffer */
374*6236dae4SAndroid Build Coastguard Worker       size_t charsize = 1;
375*6236dae4SAndroid Build Coastguard Worker       unsigned int wc = 0;
376*6236dae4SAndroid Build Coastguard Worker 
377*6236dae4SAndroid Build Coastguard Worker       switch(size) {
378*6236dae4SAndroid Build Coastguard Worker       case 4:
379*6236dae4SAndroid Build Coastguard Worker         wc = (wc << 8) | *(const unsigned char *) from++;
380*6236dae4SAndroid Build Coastguard Worker         wc = (wc << 8) | *(const unsigned char *) from++;
381*6236dae4SAndroid Build Coastguard Worker         FALLTHROUGH();
382*6236dae4SAndroid Build Coastguard Worker       case 2:
383*6236dae4SAndroid Build Coastguard Worker         wc = (wc << 8) | *(const unsigned char *) from++;
384*6236dae4SAndroid Build Coastguard Worker         FALLTHROUGH();
385*6236dae4SAndroid Build Coastguard Worker       default: /* case 1: */
386*6236dae4SAndroid Build Coastguard Worker         wc = (wc << 8) | *(const unsigned char *) from++;
387*6236dae4SAndroid Build Coastguard Worker       }
388*6236dae4SAndroid Build Coastguard Worker       if(wc >= 0x00000080) {
389*6236dae4SAndroid Build Coastguard Worker         if(wc >= 0x00000800) {
390*6236dae4SAndroid Build Coastguard Worker           if(wc >= 0x00010000) {
391*6236dae4SAndroid Build Coastguard Worker             if(wc >= 0x00200000) {
392*6236dae4SAndroid Build Coastguard Worker               /* Invalid char. size for target encoding. */
393*6236dae4SAndroid Build Coastguard Worker               return CURLE_WEIRD_SERVER_REPLY;
394*6236dae4SAndroid Build Coastguard Worker             }
395*6236dae4SAndroid Build Coastguard Worker             buf[3] = (char) (0x80 | (wc & 0x3F));
396*6236dae4SAndroid Build Coastguard Worker             wc = (wc >> 6) | 0x00010000;
397*6236dae4SAndroid Build Coastguard Worker             charsize++;
398*6236dae4SAndroid Build Coastguard Worker           }
399*6236dae4SAndroid Build Coastguard Worker           buf[2] = (char) (0x80 | (wc & 0x3F));
400*6236dae4SAndroid Build Coastguard Worker           wc = (wc >> 6) | 0x00000800;
401*6236dae4SAndroid Build Coastguard Worker           charsize++;
402*6236dae4SAndroid Build Coastguard Worker         }
403*6236dae4SAndroid Build Coastguard Worker         buf[1] = (char) (0x80 | (wc & 0x3F));
404*6236dae4SAndroid Build Coastguard Worker         wc = (wc >> 6) | 0x000000C0;
405*6236dae4SAndroid Build Coastguard Worker         charsize++;
406*6236dae4SAndroid Build Coastguard Worker       }
407*6236dae4SAndroid Build Coastguard Worker       buf[0] = (char) wc;
408*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(to, buf, charsize);
409*6236dae4SAndroid Build Coastguard Worker     }
410*6236dae4SAndroid Build Coastguard Worker   }
411*6236dae4SAndroid Build Coastguard Worker   return result;
412*6236dae4SAndroid Build Coastguard Worker }
413*6236dae4SAndroid Build Coastguard Worker 
414*6236dae4SAndroid Build Coastguard Worker /*
415*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 OID into its dotted string representation.
416*6236dae4SAndroid Build Coastguard Worker  *
417*6236dae4SAndroid Build Coastguard Worker  * Return error code.
418*6236dae4SAndroid Build Coastguard Worker  */
encodeOID(struct dynbuf * store,const char * beg,const char * end)419*6236dae4SAndroid Build Coastguard Worker static CURLcode encodeOID(struct dynbuf *store,
420*6236dae4SAndroid Build Coastguard Worker                           const char *beg, const char *end)
421*6236dae4SAndroid Build Coastguard Worker {
422*6236dae4SAndroid Build Coastguard Worker   unsigned int x;
423*6236dae4SAndroid Build Coastguard Worker   unsigned int y;
424*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
425*6236dae4SAndroid Build Coastguard Worker 
426*6236dae4SAndroid Build Coastguard Worker   /* Process the first two numbers. */
427*6236dae4SAndroid Build Coastguard Worker   y = *(const unsigned char *) beg++;
428*6236dae4SAndroid Build Coastguard Worker   x = y / 40;
429*6236dae4SAndroid Build Coastguard Worker   y -= x * 40;
430*6236dae4SAndroid Build Coastguard Worker 
431*6236dae4SAndroid Build Coastguard Worker   result = Curl_dyn_addf(store, "%u.%u", x, y);
432*6236dae4SAndroid Build Coastguard Worker   if(result)
433*6236dae4SAndroid Build Coastguard Worker     return result;
434*6236dae4SAndroid Build Coastguard Worker 
435*6236dae4SAndroid Build Coastguard Worker   /* Process the trailing numbers. */
436*6236dae4SAndroid Build Coastguard Worker   while(beg < end) {
437*6236dae4SAndroid Build Coastguard Worker     x = 0;
438*6236dae4SAndroid Build Coastguard Worker     do {
439*6236dae4SAndroid Build Coastguard Worker       if(x & 0xFF000000)
440*6236dae4SAndroid Build Coastguard Worker         return 0;
441*6236dae4SAndroid Build Coastguard Worker       y = *(const unsigned char *) beg++;
442*6236dae4SAndroid Build Coastguard Worker       x = (x << 7) | (y & 0x7F);
443*6236dae4SAndroid Build Coastguard Worker     } while(y & 0x80);
444*6236dae4SAndroid Build Coastguard Worker     result = Curl_dyn_addf(store, ".%u", x);
445*6236dae4SAndroid Build Coastguard Worker   }
446*6236dae4SAndroid Build Coastguard Worker   return result;
447*6236dae4SAndroid Build Coastguard Worker }
448*6236dae4SAndroid Build Coastguard Worker 
449*6236dae4SAndroid Build Coastguard Worker /*
450*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 OID into its dotted or symbolic string representation.
451*6236dae4SAndroid Build Coastguard Worker  *
452*6236dae4SAndroid Build Coastguard Worker  * Return error code.
453*6236dae4SAndroid Build Coastguard Worker  */
454*6236dae4SAndroid Build Coastguard Worker 
OID2str(struct dynbuf * store,const char * beg,const char * end,bool symbolic)455*6236dae4SAndroid Build Coastguard Worker static CURLcode OID2str(struct dynbuf *store,
456*6236dae4SAndroid Build Coastguard Worker                         const char *beg, const char *end, bool symbolic)
457*6236dae4SAndroid Build Coastguard Worker {
458*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
459*6236dae4SAndroid Build Coastguard Worker   if(beg < end) {
460*6236dae4SAndroid Build Coastguard Worker     if(symbolic) {
461*6236dae4SAndroid Build Coastguard Worker       struct dynbuf buf;
462*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_init(&buf, CURL_X509_STR_MAX);
463*6236dae4SAndroid Build Coastguard Worker       result = encodeOID(&buf, beg, end);
464*6236dae4SAndroid Build Coastguard Worker 
465*6236dae4SAndroid Build Coastguard Worker       if(!result) {
466*6236dae4SAndroid Build Coastguard Worker         const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf));
467*6236dae4SAndroid Build Coastguard Worker         if(op)
468*6236dae4SAndroid Build Coastguard Worker           result = Curl_dyn_add(store, op->textoid);
469*6236dae4SAndroid Build Coastguard Worker         else
470*6236dae4SAndroid Build Coastguard Worker           result = Curl_dyn_add(store, Curl_dyn_ptr(&buf));
471*6236dae4SAndroid Build Coastguard Worker         Curl_dyn_free(&buf);
472*6236dae4SAndroid Build Coastguard Worker       }
473*6236dae4SAndroid Build Coastguard Worker     }
474*6236dae4SAndroid Build Coastguard Worker     else
475*6236dae4SAndroid Build Coastguard Worker       result = encodeOID(store, beg, end);
476*6236dae4SAndroid Build Coastguard Worker   }
477*6236dae4SAndroid Build Coastguard Worker   return result;
478*6236dae4SAndroid Build Coastguard Worker }
479*6236dae4SAndroid Build Coastguard Worker 
GTime2str(struct dynbuf * store,const char * beg,const char * end)480*6236dae4SAndroid Build Coastguard Worker static CURLcode GTime2str(struct dynbuf *store,
481*6236dae4SAndroid Build Coastguard Worker                           const char *beg, const char *end)
482*6236dae4SAndroid Build Coastguard Worker {
483*6236dae4SAndroid Build Coastguard Worker   const char *tzp;
484*6236dae4SAndroid Build Coastguard Worker   const char *fracp;
485*6236dae4SAndroid Build Coastguard Worker   char sec1, sec2;
486*6236dae4SAndroid Build Coastguard Worker   size_t fracl;
487*6236dae4SAndroid Build Coastguard Worker   size_t tzl;
488*6236dae4SAndroid Build Coastguard Worker   const char *sep = "";
489*6236dae4SAndroid Build Coastguard Worker 
490*6236dae4SAndroid Build Coastguard Worker   /* Convert an ASN.1 Generalized time to a printable string.
491*6236dae4SAndroid Build Coastguard Worker      Return the dynamically allocated string, or NULL if an error occurs. */
492*6236dae4SAndroid Build Coastguard Worker 
493*6236dae4SAndroid Build Coastguard Worker   for(fracp = beg; fracp < end && ISDIGIT(*fracp); fracp++)
494*6236dae4SAndroid Build Coastguard Worker     ;
495*6236dae4SAndroid Build Coastguard Worker 
496*6236dae4SAndroid Build Coastguard Worker   /* Get seconds digits. */
497*6236dae4SAndroid Build Coastguard Worker   sec1 = '0';
498*6236dae4SAndroid Build Coastguard Worker   switch(fracp - beg - 12) {
499*6236dae4SAndroid Build Coastguard Worker   case 0:
500*6236dae4SAndroid Build Coastguard Worker     sec2 = '0';
501*6236dae4SAndroid Build Coastguard Worker     break;
502*6236dae4SAndroid Build Coastguard Worker   case 2:
503*6236dae4SAndroid Build Coastguard Worker     sec1 = fracp[-2];
504*6236dae4SAndroid Build Coastguard Worker     FALLTHROUGH();
505*6236dae4SAndroid Build Coastguard Worker   case 1:
506*6236dae4SAndroid Build Coastguard Worker     sec2 = fracp[-1];
507*6236dae4SAndroid Build Coastguard Worker     break;
508*6236dae4SAndroid Build Coastguard Worker   default:
509*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
510*6236dae4SAndroid Build Coastguard Worker   }
511*6236dae4SAndroid Build Coastguard Worker 
512*6236dae4SAndroid Build Coastguard Worker   /* timezone follows optional fractional seconds. */
513*6236dae4SAndroid Build Coastguard Worker   tzp = fracp;
514*6236dae4SAndroid Build Coastguard Worker   fracl = 0; /* no fractional seconds detected so far */
515*6236dae4SAndroid Build Coastguard Worker   if(fracp < end && (*fracp == '.' || *fracp == ',')) {
516*6236dae4SAndroid Build Coastguard Worker     /* Have fractional seconds, e.g. "[.,]\d+". How many? */
517*6236dae4SAndroid Build Coastguard Worker     fracp++; /* should be a digit char or BAD ARGUMENT */
518*6236dae4SAndroid Build Coastguard Worker     tzp = fracp;
519*6236dae4SAndroid Build Coastguard Worker     while(tzp < end && ISDIGIT(*tzp))
520*6236dae4SAndroid Build Coastguard Worker       tzp++;
521*6236dae4SAndroid Build Coastguard Worker     if(tzp == fracp) /* never looped, no digit after [.,] */
522*6236dae4SAndroid Build Coastguard Worker       return CURLE_BAD_FUNCTION_ARGUMENT;
523*6236dae4SAndroid Build Coastguard Worker     fracl = tzp - fracp; /* number of fractional sec digits */
524*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(fracl > 0);
525*6236dae4SAndroid Build Coastguard Worker     /* Strip trailing zeroes in fractional seconds.
526*6236dae4SAndroid Build Coastguard Worker      * May reduce fracl to 0 if only '0's are present. */
527*6236dae4SAndroid Build Coastguard Worker     while(fracl && fracp[fracl - 1] == '0')
528*6236dae4SAndroid Build Coastguard Worker       fracl--;
529*6236dae4SAndroid Build Coastguard Worker   }
530*6236dae4SAndroid Build Coastguard Worker 
531*6236dae4SAndroid Build Coastguard Worker   /* Process timezone. */
532*6236dae4SAndroid Build Coastguard Worker   if(tzp >= end) {
533*6236dae4SAndroid Build Coastguard Worker     tzp = "";
534*6236dae4SAndroid Build Coastguard Worker     tzl = 0;
535*6236dae4SAndroid Build Coastguard Worker   }
536*6236dae4SAndroid Build Coastguard Worker   else if(*tzp == 'Z') {
537*6236dae4SAndroid Build Coastguard Worker     sep = " ";
538*6236dae4SAndroid Build Coastguard Worker     tzp = "GMT";
539*6236dae4SAndroid Build Coastguard Worker     tzl = 3;
540*6236dae4SAndroid Build Coastguard Worker   }
541*6236dae4SAndroid Build Coastguard Worker   else if((*tzp == '+') || (*tzp == '-')) {
542*6236dae4SAndroid Build Coastguard Worker     sep = " UTC";
543*6236dae4SAndroid Build Coastguard Worker     tzl = end - tzp;
544*6236dae4SAndroid Build Coastguard Worker   }
545*6236dae4SAndroid Build Coastguard Worker   else {
546*6236dae4SAndroid Build Coastguard Worker     sep = " ";
547*6236dae4SAndroid Build Coastguard Worker     tzl = end - tzp;
548*6236dae4SAndroid Build Coastguard Worker   }
549*6236dae4SAndroid Build Coastguard Worker 
550*6236dae4SAndroid Build Coastguard Worker   return Curl_dyn_addf(store,
551*6236dae4SAndroid Build Coastguard Worker                        "%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
552*6236dae4SAndroid Build Coastguard Worker                        beg, beg + 4, beg + 6,
553*6236dae4SAndroid Build Coastguard Worker                        beg + 8, beg + 10, sec1, sec2,
554*6236dae4SAndroid Build Coastguard Worker                        fracl ? ".": "", (int)fracl, fracp,
555*6236dae4SAndroid Build Coastguard Worker                        sep, (int)tzl, tzp);
556*6236dae4SAndroid Build Coastguard Worker }
557*6236dae4SAndroid Build Coastguard Worker 
558*6236dae4SAndroid Build Coastguard Worker #ifdef UNITTESTS
559*6236dae4SAndroid Build Coastguard Worker /* used by unit1656.c */
Curl_x509_GTime2str(struct dynbuf * store,const char * beg,const char * end)560*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_x509_GTime2str(struct dynbuf *store,
561*6236dae4SAndroid Build Coastguard Worker                              const char *beg, const char *end)
562*6236dae4SAndroid Build Coastguard Worker {
563*6236dae4SAndroid Build Coastguard Worker   return GTime2str(store, beg, end);
564*6236dae4SAndroid Build Coastguard Worker }
565*6236dae4SAndroid Build Coastguard Worker #endif
566*6236dae4SAndroid Build Coastguard Worker 
567*6236dae4SAndroid Build Coastguard Worker /*
568*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 UTC time to a printable string.
569*6236dae4SAndroid Build Coastguard Worker  *
570*6236dae4SAndroid Build Coastguard Worker  * Return error code.
571*6236dae4SAndroid Build Coastguard Worker  */
UTime2str(struct dynbuf * store,const char * beg,const char * end)572*6236dae4SAndroid Build Coastguard Worker static CURLcode UTime2str(struct dynbuf *store,
573*6236dae4SAndroid Build Coastguard Worker                              const char *beg, const char *end)
574*6236dae4SAndroid Build Coastguard Worker {
575*6236dae4SAndroid Build Coastguard Worker   const char *tzp;
576*6236dae4SAndroid Build Coastguard Worker   size_t tzl;
577*6236dae4SAndroid Build Coastguard Worker   const char *sec;
578*6236dae4SAndroid Build Coastguard Worker 
579*6236dae4SAndroid Build Coastguard Worker   for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
580*6236dae4SAndroid Build Coastguard Worker     ;
581*6236dae4SAndroid Build Coastguard Worker   /* Get the seconds. */
582*6236dae4SAndroid Build Coastguard Worker   sec = beg + 10;
583*6236dae4SAndroid Build Coastguard Worker   switch(tzp - sec) {
584*6236dae4SAndroid Build Coastguard Worker   case 0:
585*6236dae4SAndroid Build Coastguard Worker     sec = "00";
586*6236dae4SAndroid Build Coastguard Worker     FALLTHROUGH();
587*6236dae4SAndroid Build Coastguard Worker   case 2:
588*6236dae4SAndroid Build Coastguard Worker     break;
589*6236dae4SAndroid Build Coastguard Worker   default:
590*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
591*6236dae4SAndroid Build Coastguard Worker   }
592*6236dae4SAndroid Build Coastguard Worker 
593*6236dae4SAndroid Build Coastguard Worker   /* Process timezone. */
594*6236dae4SAndroid Build Coastguard Worker   if(tzp >= end)
595*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
596*6236dae4SAndroid Build Coastguard Worker   if(*tzp == 'Z') {
597*6236dae4SAndroid Build Coastguard Worker     tzp = "GMT";
598*6236dae4SAndroid Build Coastguard Worker     end = tzp + 3;
599*6236dae4SAndroid Build Coastguard Worker   }
600*6236dae4SAndroid Build Coastguard Worker   else
601*6236dae4SAndroid Build Coastguard Worker     tzp++;
602*6236dae4SAndroid Build Coastguard Worker 
603*6236dae4SAndroid Build Coastguard Worker   tzl = end - tzp;
604*6236dae4SAndroid Build Coastguard Worker   return Curl_dyn_addf(store, "%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
605*6236dae4SAndroid Build Coastguard Worker                        20 - (*beg >= '5'), beg, beg + 2, beg + 4,
606*6236dae4SAndroid Build Coastguard Worker                        beg + 6, beg + 8, sec,
607*6236dae4SAndroid Build Coastguard Worker                        (int)tzl, tzp);
608*6236dae4SAndroid Build Coastguard Worker }
609*6236dae4SAndroid Build Coastguard Worker 
610*6236dae4SAndroid Build Coastguard Worker /*
611*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 element to a printable string.
612*6236dae4SAndroid Build Coastguard Worker  *
613*6236dae4SAndroid Build Coastguard Worker  * Return error
614*6236dae4SAndroid Build Coastguard Worker  */
ASN1tostr(struct dynbuf * store,struct Curl_asn1Element * elem,int type)615*6236dae4SAndroid Build Coastguard Worker static CURLcode ASN1tostr(struct dynbuf *store,
616*6236dae4SAndroid Build Coastguard Worker                           struct Curl_asn1Element *elem, int type)
617*6236dae4SAndroid Build Coastguard Worker {
618*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
619*6236dae4SAndroid Build Coastguard Worker   if(elem->constructed)
620*6236dae4SAndroid Build Coastguard Worker     return result; /* No conversion of structured elements. */
621*6236dae4SAndroid Build Coastguard Worker 
622*6236dae4SAndroid Build Coastguard Worker   if(!type)
623*6236dae4SAndroid Build Coastguard Worker     type = elem->tag;   /* Type not forced: use element tag as type. */
624*6236dae4SAndroid Build Coastguard Worker 
625*6236dae4SAndroid Build Coastguard Worker   switch(type) {
626*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_BOOLEAN:
627*6236dae4SAndroid Build Coastguard Worker     result = bool2str(store, elem->beg, elem->end);
628*6236dae4SAndroid Build Coastguard Worker     break;
629*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_INTEGER:
630*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_ENUMERATED:
631*6236dae4SAndroid Build Coastguard Worker     result = int2str(store, elem->beg, elem->end);
632*6236dae4SAndroid Build Coastguard Worker     break;
633*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_BIT_STRING:
634*6236dae4SAndroid Build Coastguard Worker     result = bit2str(store, elem->beg, elem->end);
635*6236dae4SAndroid Build Coastguard Worker     break;
636*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_OCTET_STRING:
637*6236dae4SAndroid Build Coastguard Worker     result = octet2str(store, elem->beg, elem->end);
638*6236dae4SAndroid Build Coastguard Worker     break;
639*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_NULL:
640*6236dae4SAndroid Build Coastguard Worker     result = Curl_dyn_addn(store, "", 1);
641*6236dae4SAndroid Build Coastguard Worker     break;
642*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_OBJECT_IDENTIFIER:
643*6236dae4SAndroid Build Coastguard Worker     result = OID2str(store, elem->beg, elem->end, TRUE);
644*6236dae4SAndroid Build Coastguard Worker     break;
645*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_UTC_TIME:
646*6236dae4SAndroid Build Coastguard Worker     result = UTime2str(store, elem->beg, elem->end);
647*6236dae4SAndroid Build Coastguard Worker     break;
648*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_GENERALIZED_TIME:
649*6236dae4SAndroid Build Coastguard Worker     result = GTime2str(store, elem->beg, elem->end);
650*6236dae4SAndroid Build Coastguard Worker     break;
651*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_UTF8_STRING:
652*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_NUMERIC_STRING:
653*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_PRINTABLE_STRING:
654*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_TELETEX_STRING:
655*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_IA5_STRING:
656*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_VISIBLE_STRING:
657*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_UNIVERSAL_STRING:
658*6236dae4SAndroid Build Coastguard Worker   case CURL_ASN1_BMP_STRING:
659*6236dae4SAndroid Build Coastguard Worker     result = utf8asn1str(store, type, elem->beg, elem->end);
660*6236dae4SAndroid Build Coastguard Worker     break;
661*6236dae4SAndroid Build Coastguard Worker   }
662*6236dae4SAndroid Build Coastguard Worker 
663*6236dae4SAndroid Build Coastguard Worker   return result;
664*6236dae4SAndroid Build Coastguard Worker }
665*6236dae4SAndroid Build Coastguard Worker 
666*6236dae4SAndroid Build Coastguard Worker /*
667*6236dae4SAndroid Build Coastguard Worker  * ASCII encode distinguished name at `dn' into the store dynbuf.
668*6236dae4SAndroid Build Coastguard Worker  *
669*6236dae4SAndroid Build Coastguard Worker  * Returns error.
670*6236dae4SAndroid Build Coastguard Worker  */
encodeDN(struct dynbuf * store,struct Curl_asn1Element * dn)671*6236dae4SAndroid Build Coastguard Worker static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn)
672*6236dae4SAndroid Build Coastguard Worker {
673*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element rdn;
674*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element atv;
675*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element oid;
676*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element value;
677*6236dae4SAndroid Build Coastguard Worker   const char *p1;
678*6236dae4SAndroid Build Coastguard Worker   const char *p2;
679*6236dae4SAndroid Build Coastguard Worker   const char *p3;
680*6236dae4SAndroid Build Coastguard Worker   const char *str;
681*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
682*6236dae4SAndroid Build Coastguard Worker   bool added = FALSE;
683*6236dae4SAndroid Build Coastguard Worker   struct dynbuf temp;
684*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&temp, CURL_X509_STR_MAX);
685*6236dae4SAndroid Build Coastguard Worker 
686*6236dae4SAndroid Build Coastguard Worker   for(p1 = dn->beg; p1 < dn->end;) {
687*6236dae4SAndroid Build Coastguard Worker     p1 = getASN1Element(&rdn, p1, dn->end);
688*6236dae4SAndroid Build Coastguard Worker     if(!p1) {
689*6236dae4SAndroid Build Coastguard Worker       result = CURLE_BAD_FUNCTION_ARGUMENT;
690*6236dae4SAndroid Build Coastguard Worker       goto error;
691*6236dae4SAndroid Build Coastguard Worker     }
692*6236dae4SAndroid Build Coastguard Worker     for(p2 = rdn.beg; p2 < rdn.end;) {
693*6236dae4SAndroid Build Coastguard Worker       p2 = getASN1Element(&atv, p2, rdn.end);
694*6236dae4SAndroid Build Coastguard Worker       if(!p2) {
695*6236dae4SAndroid Build Coastguard Worker         result = CURLE_BAD_FUNCTION_ARGUMENT;
696*6236dae4SAndroid Build Coastguard Worker         goto error;
697*6236dae4SAndroid Build Coastguard Worker       }
698*6236dae4SAndroid Build Coastguard Worker       p3 = getASN1Element(&oid, atv.beg, atv.end);
699*6236dae4SAndroid Build Coastguard Worker       if(!p3) {
700*6236dae4SAndroid Build Coastguard Worker         result = CURLE_BAD_FUNCTION_ARGUMENT;
701*6236dae4SAndroid Build Coastguard Worker         goto error;
702*6236dae4SAndroid Build Coastguard Worker       }
703*6236dae4SAndroid Build Coastguard Worker       if(!getASN1Element(&value, p3, atv.end)) {
704*6236dae4SAndroid Build Coastguard Worker         result = CURLE_BAD_FUNCTION_ARGUMENT;
705*6236dae4SAndroid Build Coastguard Worker         goto error;
706*6236dae4SAndroid Build Coastguard Worker       }
707*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_reset(&temp);
708*6236dae4SAndroid Build Coastguard Worker       result = ASN1tostr(&temp, &oid, 0);
709*6236dae4SAndroid Build Coastguard Worker       if(result)
710*6236dae4SAndroid Build Coastguard Worker         goto error;
711*6236dae4SAndroid Build Coastguard Worker 
712*6236dae4SAndroid Build Coastguard Worker       str = Curl_dyn_ptr(&temp);
713*6236dae4SAndroid Build Coastguard Worker 
714*6236dae4SAndroid Build Coastguard Worker       if(!str) {
715*6236dae4SAndroid Build Coastguard Worker         result = CURLE_BAD_FUNCTION_ARGUMENT;
716*6236dae4SAndroid Build Coastguard Worker         goto error;
717*6236dae4SAndroid Build Coastguard Worker       }
718*6236dae4SAndroid Build Coastguard Worker 
719*6236dae4SAndroid Build Coastguard Worker       /* Encode delimiter.
720*6236dae4SAndroid Build Coastguard Worker          If attribute has a short uppercase name, delimiter is ", ". */
721*6236dae4SAndroid Build Coastguard Worker       for(p3 = str; ISUPPER(*p3); p3++)
722*6236dae4SAndroid Build Coastguard Worker         ;
723*6236dae4SAndroid Build Coastguard Worker       if(added) {
724*6236dae4SAndroid Build Coastguard Worker         if(p3 - str > 2)
725*6236dae4SAndroid Build Coastguard Worker           result = Curl_dyn_addn(store, "/", 1);
726*6236dae4SAndroid Build Coastguard Worker         else
727*6236dae4SAndroid Build Coastguard Worker           result = Curl_dyn_addn(store, ", ", 2);
728*6236dae4SAndroid Build Coastguard Worker         if(result)
729*6236dae4SAndroid Build Coastguard Worker           goto error;
730*6236dae4SAndroid Build Coastguard Worker       }
731*6236dae4SAndroid Build Coastguard Worker 
732*6236dae4SAndroid Build Coastguard Worker       /* Encode attribute name. */
733*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_add(store, str);
734*6236dae4SAndroid Build Coastguard Worker       if(result)
735*6236dae4SAndroid Build Coastguard Worker         goto error;
736*6236dae4SAndroid Build Coastguard Worker 
737*6236dae4SAndroid Build Coastguard Worker       /* Generate equal sign. */
738*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(store, "=", 1);
739*6236dae4SAndroid Build Coastguard Worker       if(result)
740*6236dae4SAndroid Build Coastguard Worker         goto error;
741*6236dae4SAndroid Build Coastguard Worker 
742*6236dae4SAndroid Build Coastguard Worker       /* Generate value. */
743*6236dae4SAndroid Build Coastguard Worker       result = ASN1tostr(store, &value, 0);
744*6236dae4SAndroid Build Coastguard Worker       if(result)
745*6236dae4SAndroid Build Coastguard Worker         goto error;
746*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_reset(&temp);
747*6236dae4SAndroid Build Coastguard Worker       added = TRUE; /* use separator for next */
748*6236dae4SAndroid Build Coastguard Worker     }
749*6236dae4SAndroid Build Coastguard Worker   }
750*6236dae4SAndroid Build Coastguard Worker error:
751*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&temp);
752*6236dae4SAndroid Build Coastguard Worker 
753*6236dae4SAndroid Build Coastguard Worker   return result;
754*6236dae4SAndroid Build Coastguard Worker }
755*6236dae4SAndroid Build Coastguard Worker 
756*6236dae4SAndroid Build Coastguard Worker #endif /* WANT_EXTRACT_CERTINFO */
757*6236dae4SAndroid Build Coastguard Worker 
758*6236dae4SAndroid Build Coastguard Worker #ifdef WANT_PARSEX509
759*6236dae4SAndroid Build Coastguard Worker /*
760*6236dae4SAndroid Build Coastguard Worker  * ASN.1 parse an X509 certificate into structure subfields.
761*6236dae4SAndroid Build Coastguard Worker  * Syntax is assumed to have already been checked by the SSL backend.
762*6236dae4SAndroid Build Coastguard Worker  * See RFC 5280.
763*6236dae4SAndroid Build Coastguard Worker  */
Curl_parseX509(struct Curl_X509certificate * cert,const char * beg,const char * end)764*6236dae4SAndroid Build Coastguard Worker int Curl_parseX509(struct Curl_X509certificate *cert,
765*6236dae4SAndroid Build Coastguard Worker                    const char *beg, const char *end)
766*6236dae4SAndroid Build Coastguard Worker {
767*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element elem;
768*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element tbsCertificate;
769*6236dae4SAndroid Build Coastguard Worker   const char *ccp;
770*6236dae4SAndroid Build Coastguard Worker   static const char defaultVersion = 0;  /* v1. */
771*6236dae4SAndroid Build Coastguard Worker 
772*6236dae4SAndroid Build Coastguard Worker   cert->certificate.header = NULL;
773*6236dae4SAndroid Build Coastguard Worker   cert->certificate.beg = beg;
774*6236dae4SAndroid Build Coastguard Worker   cert->certificate.end = end;
775*6236dae4SAndroid Build Coastguard Worker 
776*6236dae4SAndroid Build Coastguard Worker   /* Get the sequence content. */
777*6236dae4SAndroid Build Coastguard Worker   if(!getASN1Element(&elem, beg, end))
778*6236dae4SAndroid Build Coastguard Worker     return -1;  /* Invalid bounds/size. */
779*6236dae4SAndroid Build Coastguard Worker   beg = elem.beg;
780*6236dae4SAndroid Build Coastguard Worker   end = elem.end;
781*6236dae4SAndroid Build Coastguard Worker 
782*6236dae4SAndroid Build Coastguard Worker   /* Get tbsCertificate. */
783*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&tbsCertificate, beg, end);
784*6236dae4SAndroid Build Coastguard Worker   if(!beg)
785*6236dae4SAndroid Build Coastguard Worker     return -1;
786*6236dae4SAndroid Build Coastguard Worker   /* Skip the signatureAlgorithm. */
787*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
788*6236dae4SAndroid Build Coastguard Worker   if(!beg)
789*6236dae4SAndroid Build Coastguard Worker     return -1;
790*6236dae4SAndroid Build Coastguard Worker   /* Get the signatureValue. */
791*6236dae4SAndroid Build Coastguard Worker   if(!getASN1Element(&cert->signature, beg, end))
792*6236dae4SAndroid Build Coastguard Worker     return -1;
793*6236dae4SAndroid Build Coastguard Worker 
794*6236dae4SAndroid Build Coastguard Worker   /* Parse TBSCertificate. */
795*6236dae4SAndroid Build Coastguard Worker   beg = tbsCertificate.beg;
796*6236dae4SAndroid Build Coastguard Worker   end = tbsCertificate.end;
797*6236dae4SAndroid Build Coastguard Worker   /* Get optional version, get serialNumber. */
798*6236dae4SAndroid Build Coastguard Worker   cert->version.header = NULL;
799*6236dae4SAndroid Build Coastguard Worker   cert->version.beg = &defaultVersion;
800*6236dae4SAndroid Build Coastguard Worker   cert->version.end = &defaultVersion + sizeof(defaultVersion);
801*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&elem, beg, end);
802*6236dae4SAndroid Build Coastguard Worker   if(!beg)
803*6236dae4SAndroid Build Coastguard Worker     return -1;
804*6236dae4SAndroid Build Coastguard Worker   if(elem.tag == 0) {
805*6236dae4SAndroid Build Coastguard Worker     if(!getASN1Element(&cert->version, elem.beg, elem.end))
806*6236dae4SAndroid Build Coastguard Worker       return -1;
807*6236dae4SAndroid Build Coastguard Worker     beg = getASN1Element(&elem, beg, end);
808*6236dae4SAndroid Build Coastguard Worker     if(!beg)
809*6236dae4SAndroid Build Coastguard Worker       return -1;
810*6236dae4SAndroid Build Coastguard Worker   }
811*6236dae4SAndroid Build Coastguard Worker   cert->serialNumber = elem;
812*6236dae4SAndroid Build Coastguard Worker   /* Get signature algorithm. */
813*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
814*6236dae4SAndroid Build Coastguard Worker   /* Get issuer. */
815*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&cert->issuer, beg, end);
816*6236dae4SAndroid Build Coastguard Worker   if(!beg)
817*6236dae4SAndroid Build Coastguard Worker     return -1;
818*6236dae4SAndroid Build Coastguard Worker   /* Get notBefore and notAfter. */
819*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&elem, beg, end);
820*6236dae4SAndroid Build Coastguard Worker   if(!beg)
821*6236dae4SAndroid Build Coastguard Worker     return -1;
822*6236dae4SAndroid Build Coastguard Worker   ccp = getASN1Element(&cert->notBefore, elem.beg, elem.end);
823*6236dae4SAndroid Build Coastguard Worker   if(!ccp)
824*6236dae4SAndroid Build Coastguard Worker     return -1;
825*6236dae4SAndroid Build Coastguard Worker   if(!getASN1Element(&cert->notAfter, ccp, elem.end))
826*6236dae4SAndroid Build Coastguard Worker     return -1;
827*6236dae4SAndroid Build Coastguard Worker   /* Get subject. */
828*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&cert->subject, beg, end);
829*6236dae4SAndroid Build Coastguard Worker   if(!beg)
830*6236dae4SAndroid Build Coastguard Worker     return -1;
831*6236dae4SAndroid Build Coastguard Worker   /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
832*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
833*6236dae4SAndroid Build Coastguard Worker   if(!beg)
834*6236dae4SAndroid Build Coastguard Worker     return -1;
835*6236dae4SAndroid Build Coastguard Worker   ccp = getASN1Element(&cert->subjectPublicKeyAlgorithm,
836*6236dae4SAndroid Build Coastguard Worker                        cert->subjectPublicKeyInfo.beg,
837*6236dae4SAndroid Build Coastguard Worker                        cert->subjectPublicKeyInfo.end);
838*6236dae4SAndroid Build Coastguard Worker   if(!ccp)
839*6236dae4SAndroid Build Coastguard Worker     return -1;
840*6236dae4SAndroid Build Coastguard Worker   if(!getASN1Element(&cert->subjectPublicKey, ccp,
841*6236dae4SAndroid Build Coastguard Worker                      cert->subjectPublicKeyInfo.end))
842*6236dae4SAndroid Build Coastguard Worker     return -1;
843*6236dae4SAndroid Build Coastguard Worker   /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
844*6236dae4SAndroid Build Coastguard Worker   cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
845*6236dae4SAndroid Build Coastguard Worker   cert->extensions.tag = elem.tag = 0;
846*6236dae4SAndroid Build Coastguard Worker   cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
847*6236dae4SAndroid Build Coastguard Worker   cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
848*6236dae4SAndroid Build Coastguard Worker   cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
849*6236dae4SAndroid Build Coastguard Worker   cert->extensions.header = NULL;
850*6236dae4SAndroid Build Coastguard Worker   cert->extensions.beg = cert->extensions.end = "";
851*6236dae4SAndroid Build Coastguard Worker   if(beg < end) {
852*6236dae4SAndroid Build Coastguard Worker     beg = getASN1Element(&elem, beg, end);
853*6236dae4SAndroid Build Coastguard Worker     if(!beg)
854*6236dae4SAndroid Build Coastguard Worker       return -1;
855*6236dae4SAndroid Build Coastguard Worker   }
856*6236dae4SAndroid Build Coastguard Worker   if(elem.tag == 1) {
857*6236dae4SAndroid Build Coastguard Worker     cert->issuerUniqueID = elem;
858*6236dae4SAndroid Build Coastguard Worker     if(beg < end) {
859*6236dae4SAndroid Build Coastguard Worker       beg = getASN1Element(&elem, beg, end);
860*6236dae4SAndroid Build Coastguard Worker       if(!beg)
861*6236dae4SAndroid Build Coastguard Worker         return -1;
862*6236dae4SAndroid Build Coastguard Worker     }
863*6236dae4SAndroid Build Coastguard Worker   }
864*6236dae4SAndroid Build Coastguard Worker   if(elem.tag == 2) {
865*6236dae4SAndroid Build Coastguard Worker     cert->subjectUniqueID = elem;
866*6236dae4SAndroid Build Coastguard Worker     if(beg < end) {
867*6236dae4SAndroid Build Coastguard Worker       beg = getASN1Element(&elem, beg, end);
868*6236dae4SAndroid Build Coastguard Worker       if(!beg)
869*6236dae4SAndroid Build Coastguard Worker         return -1;
870*6236dae4SAndroid Build Coastguard Worker     }
871*6236dae4SAndroid Build Coastguard Worker   }
872*6236dae4SAndroid Build Coastguard Worker   if(elem.tag == 3)
873*6236dae4SAndroid Build Coastguard Worker     if(!getASN1Element(&cert->extensions, elem.beg, elem.end))
874*6236dae4SAndroid Build Coastguard Worker       return -1;
875*6236dae4SAndroid Build Coastguard Worker   return 0;
876*6236dae4SAndroid Build Coastguard Worker }
877*6236dae4SAndroid Build Coastguard Worker 
878*6236dae4SAndroid Build Coastguard Worker #endif /* WANT_PARSEX509 */
879*6236dae4SAndroid Build Coastguard Worker 
880*6236dae4SAndroid Build Coastguard Worker #ifdef WANT_EXTRACT_CERTINFO
881*6236dae4SAndroid Build Coastguard Worker 
dumpAlgo(struct dynbuf * store,struct Curl_asn1Element * param,const char * beg,const char * end)882*6236dae4SAndroid Build Coastguard Worker static CURLcode dumpAlgo(struct dynbuf *store,
883*6236dae4SAndroid Build Coastguard Worker                          struct Curl_asn1Element *param,
884*6236dae4SAndroid Build Coastguard Worker                          const char *beg, const char *end)
885*6236dae4SAndroid Build Coastguard Worker {
886*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element oid;
887*6236dae4SAndroid Build Coastguard Worker 
888*6236dae4SAndroid Build Coastguard Worker   /* Get algorithm parameters and return algorithm name. */
889*6236dae4SAndroid Build Coastguard Worker 
890*6236dae4SAndroid Build Coastguard Worker   beg = getASN1Element(&oid, beg, end);
891*6236dae4SAndroid Build Coastguard Worker   if(!beg)
892*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
893*6236dae4SAndroid Build Coastguard Worker   param->header = NULL;
894*6236dae4SAndroid Build Coastguard Worker   param->tag = 0;
895*6236dae4SAndroid Build Coastguard Worker   param->beg = param->end = end;
896*6236dae4SAndroid Build Coastguard Worker   if(beg < end) {
897*6236dae4SAndroid Build Coastguard Worker     const char *p = getASN1Element(param, beg, end);
898*6236dae4SAndroid Build Coastguard Worker     if(!p)
899*6236dae4SAndroid Build Coastguard Worker       return CURLE_BAD_FUNCTION_ARGUMENT;
900*6236dae4SAndroid Build Coastguard Worker   }
901*6236dae4SAndroid Build Coastguard Worker   return OID2str(store, oid.beg, oid.end, TRUE);
902*6236dae4SAndroid Build Coastguard Worker }
903*6236dae4SAndroid Build Coastguard Worker 
904*6236dae4SAndroid Build Coastguard Worker /*
905*6236dae4SAndroid Build Coastguard Worker  * This is a convenience function for push_certinfo_len that takes a zero
906*6236dae4SAndroid Build Coastguard Worker  * terminated value.
907*6236dae4SAndroid Build Coastguard Worker  */
ssl_push_certinfo(struct Curl_easy * data,int certnum,const char * label,const char * value)908*6236dae4SAndroid Build Coastguard Worker static CURLcode ssl_push_certinfo(struct Curl_easy *data,
909*6236dae4SAndroid Build Coastguard Worker                                   int certnum,
910*6236dae4SAndroid Build Coastguard Worker                                   const char *label,
911*6236dae4SAndroid Build Coastguard Worker                                   const char *value)
912*6236dae4SAndroid Build Coastguard Worker {
913*6236dae4SAndroid Build Coastguard Worker   size_t valuelen = strlen(value);
914*6236dae4SAndroid Build Coastguard Worker 
915*6236dae4SAndroid Build Coastguard Worker   return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
916*6236dae4SAndroid Build Coastguard Worker }
917*6236dae4SAndroid Build Coastguard Worker 
918*6236dae4SAndroid Build Coastguard Worker /*
919*6236dae4SAndroid Build Coastguard Worker  * This is a convenience function for push_certinfo_len that takes a
920*6236dae4SAndroid Build Coastguard Worker  * dynbuf value.
921*6236dae4SAndroid Build Coastguard Worker  *
922*6236dae4SAndroid Build Coastguard Worker  * It also does the verbose output if !certnum.
923*6236dae4SAndroid Build Coastguard Worker  */
ssl_push_certinfo_dyn(struct Curl_easy * data,int certnum,const char * label,struct dynbuf * ptr)924*6236dae4SAndroid Build Coastguard Worker static CURLcode ssl_push_certinfo_dyn(struct Curl_easy *data,
925*6236dae4SAndroid Build Coastguard Worker                                       int certnum,
926*6236dae4SAndroid Build Coastguard Worker                                       const char *label,
927*6236dae4SAndroid Build Coastguard Worker                                       struct dynbuf *ptr)
928*6236dae4SAndroid Build Coastguard Worker {
929*6236dae4SAndroid Build Coastguard Worker   size_t valuelen = Curl_dyn_len(ptr);
930*6236dae4SAndroid Build Coastguard Worker   char *value = Curl_dyn_ptr(ptr);
931*6236dae4SAndroid Build Coastguard Worker 
932*6236dae4SAndroid Build Coastguard Worker   CURLcode result = Curl_ssl_push_certinfo_len(data, certnum, label,
933*6236dae4SAndroid Build Coastguard Worker                                                value, valuelen);
934*6236dae4SAndroid Build Coastguard Worker 
935*6236dae4SAndroid Build Coastguard Worker   if(!certnum && !result)
936*6236dae4SAndroid Build Coastguard Worker     infof(data, "   %s: %s", label, value);
937*6236dae4SAndroid Build Coastguard Worker 
938*6236dae4SAndroid Build Coastguard Worker   return result;
939*6236dae4SAndroid Build Coastguard Worker }
940*6236dae4SAndroid Build Coastguard Worker 
do_pubkey_field(struct Curl_easy * data,int certnum,const char * label,struct Curl_asn1Element * elem)941*6236dae4SAndroid Build Coastguard Worker static CURLcode do_pubkey_field(struct Curl_easy *data, int certnum,
942*6236dae4SAndroid Build Coastguard Worker                                 const char *label,
943*6236dae4SAndroid Build Coastguard Worker                                 struct Curl_asn1Element *elem)
944*6236dae4SAndroid Build Coastguard Worker {
945*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
946*6236dae4SAndroid Build Coastguard Worker   struct dynbuf out;
947*6236dae4SAndroid Build Coastguard Worker 
948*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&out, CURL_X509_STR_MAX);
949*6236dae4SAndroid Build Coastguard Worker 
950*6236dae4SAndroid Build Coastguard Worker   /* Generate a certificate information record for the public key. */
951*6236dae4SAndroid Build Coastguard Worker 
952*6236dae4SAndroid Build Coastguard Worker   result = ASN1tostr(&out, elem, 0);
953*6236dae4SAndroid Build Coastguard Worker   if(!result) {
954*6236dae4SAndroid Build Coastguard Worker     if(data->set.ssl.certinfo)
955*6236dae4SAndroid Build Coastguard Worker       result = ssl_push_certinfo_dyn(data, certnum, label, &out);
956*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_free(&out);
957*6236dae4SAndroid Build Coastguard Worker   }
958*6236dae4SAndroid Build Coastguard Worker   return result;
959*6236dae4SAndroid Build Coastguard Worker }
960*6236dae4SAndroid Build Coastguard Worker 
961*6236dae4SAndroid Build Coastguard Worker /* return 0 on success, 1 on error */
do_pubkey(struct Curl_easy * data,int certnum,const char * algo,struct Curl_asn1Element * param,struct Curl_asn1Element * pubkey)962*6236dae4SAndroid Build Coastguard Worker static int do_pubkey(struct Curl_easy *data, int certnum,
963*6236dae4SAndroid Build Coastguard Worker                      const char *algo, struct Curl_asn1Element *param,
964*6236dae4SAndroid Build Coastguard Worker                      struct Curl_asn1Element *pubkey)
965*6236dae4SAndroid Build Coastguard Worker {
966*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element elem;
967*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element pk;
968*6236dae4SAndroid Build Coastguard Worker   const char *p;
969*6236dae4SAndroid Build Coastguard Worker 
970*6236dae4SAndroid Build Coastguard Worker   /* Generate all information records for the public key. */
971*6236dae4SAndroid Build Coastguard Worker 
972*6236dae4SAndroid Build Coastguard Worker   if(strcasecompare(algo, "ecPublicKey")) {
973*6236dae4SAndroid Build Coastguard Worker     /*
974*6236dae4SAndroid Build Coastguard Worker      * ECC public key is all the data, a value of type BIT STRING mapped to
975*6236dae4SAndroid Build Coastguard Worker      * OCTET STRING and should not be parsed as an ASN.1 value.
976*6236dae4SAndroid Build Coastguard Worker      */
977*6236dae4SAndroid Build Coastguard Worker     const size_t len = ((pubkey->end - pubkey->beg - 2) * 4);
978*6236dae4SAndroid Build Coastguard Worker     if(!certnum)
979*6236dae4SAndroid Build Coastguard Worker       infof(data, "   ECC Public Key (%zu bits)", len);
980*6236dae4SAndroid Build Coastguard Worker     if(data->set.ssl.certinfo) {
981*6236dae4SAndroid Build Coastguard Worker       char q[sizeof(len) * 8 / 3 + 1];
982*6236dae4SAndroid Build Coastguard Worker       (void)msnprintf(q, sizeof(q), "%zu", len);
983*6236dae4SAndroid Build Coastguard Worker       if(ssl_push_certinfo(data, certnum, "ECC Public Key", q))
984*6236dae4SAndroid Build Coastguard Worker         return 1;
985*6236dae4SAndroid Build Coastguard Worker     }
986*6236dae4SAndroid Build Coastguard Worker     return do_pubkey_field(data, certnum, "ecPublicKey", pubkey) == CURLE_OK
987*6236dae4SAndroid Build Coastguard Worker       ? 0 : 1;
988*6236dae4SAndroid Build Coastguard Worker   }
989*6236dae4SAndroid Build Coastguard Worker 
990*6236dae4SAndroid Build Coastguard Worker   /* Get the public key (single element). */
991*6236dae4SAndroid Build Coastguard Worker   if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
992*6236dae4SAndroid Build Coastguard Worker     return 1;
993*6236dae4SAndroid Build Coastguard Worker 
994*6236dae4SAndroid Build Coastguard Worker   if(strcasecompare(algo, "rsaEncryption")) {
995*6236dae4SAndroid Build Coastguard Worker     const char *q;
996*6236dae4SAndroid Build Coastguard Worker     size_t len;
997*6236dae4SAndroid Build Coastguard Worker 
998*6236dae4SAndroid Build Coastguard Worker     p = getASN1Element(&elem, pk.beg, pk.end);
999*6236dae4SAndroid Build Coastguard Worker     if(!p)
1000*6236dae4SAndroid Build Coastguard Worker       return 1;
1001*6236dae4SAndroid Build Coastguard Worker 
1002*6236dae4SAndroid Build Coastguard Worker     /* Compute key length. */
1003*6236dae4SAndroid Build Coastguard Worker     for(q = elem.beg; !*q && q < elem.end; q++)
1004*6236dae4SAndroid Build Coastguard Worker       ;
1005*6236dae4SAndroid Build Coastguard Worker     len = ((elem.end - q) * 8);
1006*6236dae4SAndroid Build Coastguard Worker     if(len) {
1007*6236dae4SAndroid Build Coastguard Worker       unsigned int i;
1008*6236dae4SAndroid Build Coastguard Worker       for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
1009*6236dae4SAndroid Build Coastguard Worker         len--;
1010*6236dae4SAndroid Build Coastguard Worker     }
1011*6236dae4SAndroid Build Coastguard Worker     if(len > 32)
1012*6236dae4SAndroid Build Coastguard Worker       elem.beg = q;     /* Strip leading zero bytes. */
1013*6236dae4SAndroid Build Coastguard Worker     if(!certnum)
1014*6236dae4SAndroid Build Coastguard Worker       infof(data, "   RSA Public Key (%zu bits)", len);
1015*6236dae4SAndroid Build Coastguard Worker     if(data->set.ssl.certinfo) {
1016*6236dae4SAndroid Build Coastguard Worker       char r[sizeof(len) * 8 / 3 + 1];
1017*6236dae4SAndroid Build Coastguard Worker       msnprintf(r, sizeof(r), "%zu", len);
1018*6236dae4SAndroid Build Coastguard Worker       if(ssl_push_certinfo(data, certnum, "RSA Public Key", r))
1019*6236dae4SAndroid Build Coastguard Worker         return 1;
1020*6236dae4SAndroid Build Coastguard Worker     }
1021*6236dae4SAndroid Build Coastguard Worker     /* Generate coefficients. */
1022*6236dae4SAndroid Build Coastguard Worker     if(do_pubkey_field(data, certnum, "rsa(n)", &elem))
1023*6236dae4SAndroid Build Coastguard Worker       return 1;
1024*6236dae4SAndroid Build Coastguard Worker     if(!getASN1Element(&elem, p, pk.end))
1025*6236dae4SAndroid Build Coastguard Worker       return 1;
1026*6236dae4SAndroid Build Coastguard Worker     if(do_pubkey_field(data, certnum, "rsa(e)", &elem))
1027*6236dae4SAndroid Build Coastguard Worker       return 1;
1028*6236dae4SAndroid Build Coastguard Worker   }
1029*6236dae4SAndroid Build Coastguard Worker   else if(strcasecompare(algo, "dsa")) {
1030*6236dae4SAndroid Build Coastguard Worker     p = getASN1Element(&elem, param->beg, param->end);
1031*6236dae4SAndroid Build Coastguard Worker     if(p) {
1032*6236dae4SAndroid Build Coastguard Worker       if(do_pubkey_field(data, certnum, "dsa(p)", &elem))
1033*6236dae4SAndroid Build Coastguard Worker         return 1;
1034*6236dae4SAndroid Build Coastguard Worker       p = getASN1Element(&elem, p, param->end);
1035*6236dae4SAndroid Build Coastguard Worker       if(p) {
1036*6236dae4SAndroid Build Coastguard Worker         if(do_pubkey_field(data, certnum, "dsa(q)", &elem))
1037*6236dae4SAndroid Build Coastguard Worker           return 1;
1038*6236dae4SAndroid Build Coastguard Worker         if(getASN1Element(&elem, p, param->end)) {
1039*6236dae4SAndroid Build Coastguard Worker           if(do_pubkey_field(data, certnum, "dsa(g)", &elem))
1040*6236dae4SAndroid Build Coastguard Worker             return 1;
1041*6236dae4SAndroid Build Coastguard Worker           if(do_pubkey_field(data, certnum, "dsa(pub_key)", &pk))
1042*6236dae4SAndroid Build Coastguard Worker             return 1;
1043*6236dae4SAndroid Build Coastguard Worker         }
1044*6236dae4SAndroid Build Coastguard Worker       }
1045*6236dae4SAndroid Build Coastguard Worker     }
1046*6236dae4SAndroid Build Coastguard Worker   }
1047*6236dae4SAndroid Build Coastguard Worker   else if(strcasecompare(algo, "dhpublicnumber")) {
1048*6236dae4SAndroid Build Coastguard Worker     p = getASN1Element(&elem, param->beg, param->end);
1049*6236dae4SAndroid Build Coastguard Worker     if(p) {
1050*6236dae4SAndroid Build Coastguard Worker       if(do_pubkey_field(data, certnum, "dh(p)", &elem))
1051*6236dae4SAndroid Build Coastguard Worker         return 1;
1052*6236dae4SAndroid Build Coastguard Worker       if(getASN1Element(&elem, param->beg, param->end)) {
1053*6236dae4SAndroid Build Coastguard Worker         if(do_pubkey_field(data, certnum, "dh(g)", &elem))
1054*6236dae4SAndroid Build Coastguard Worker           return 1;
1055*6236dae4SAndroid Build Coastguard Worker         if(do_pubkey_field(data, certnum, "dh(pub_key)", &pk))
1056*6236dae4SAndroid Build Coastguard Worker           return 1;
1057*6236dae4SAndroid Build Coastguard Worker       }
1058*6236dae4SAndroid Build Coastguard Worker     }
1059*6236dae4SAndroid Build Coastguard Worker   }
1060*6236dae4SAndroid Build Coastguard Worker   return 0;
1061*6236dae4SAndroid Build Coastguard Worker }
1062*6236dae4SAndroid Build Coastguard Worker 
1063*6236dae4SAndroid Build Coastguard Worker /*
1064*6236dae4SAndroid Build Coastguard Worker  * Convert an ASN.1 distinguished name into a printable string.
1065*6236dae4SAndroid Build Coastguard Worker  * Return error.
1066*6236dae4SAndroid Build Coastguard Worker  */
DNtostr(struct dynbuf * store,struct Curl_asn1Element * dn)1067*6236dae4SAndroid Build Coastguard Worker static CURLcode DNtostr(struct dynbuf *store,
1068*6236dae4SAndroid Build Coastguard Worker                         struct Curl_asn1Element *dn)
1069*6236dae4SAndroid Build Coastguard Worker {
1070*6236dae4SAndroid Build Coastguard Worker   return encodeDN(store, dn);
1071*6236dae4SAndroid Build Coastguard Worker }
1072*6236dae4SAndroid Build Coastguard Worker 
Curl_extract_certinfo(struct Curl_easy * data,int certnum,const char * beg,const char * end)1073*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_extract_certinfo(struct Curl_easy *data,
1074*6236dae4SAndroid Build Coastguard Worker                                int certnum,
1075*6236dae4SAndroid Build Coastguard Worker                                const char *beg,
1076*6236dae4SAndroid Build Coastguard Worker                                const char *end)
1077*6236dae4SAndroid Build Coastguard Worker {
1078*6236dae4SAndroid Build Coastguard Worker   struct Curl_X509certificate cert;
1079*6236dae4SAndroid Build Coastguard Worker   struct Curl_asn1Element param;
1080*6236dae4SAndroid Build Coastguard Worker   char *certptr;
1081*6236dae4SAndroid Build Coastguard Worker   size_t clen;
1082*6236dae4SAndroid Build Coastguard Worker   struct dynbuf out;
1083*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1084*6236dae4SAndroid Build Coastguard Worker   unsigned int version;
1085*6236dae4SAndroid Build Coastguard Worker   const char *ptr;
1086*6236dae4SAndroid Build Coastguard Worker   int rc;
1087*6236dae4SAndroid Build Coastguard Worker 
1088*6236dae4SAndroid Build Coastguard Worker   if(!data->set.ssl.certinfo)
1089*6236dae4SAndroid Build Coastguard Worker     if(certnum)
1090*6236dae4SAndroid Build Coastguard Worker       return CURLE_OK;
1091*6236dae4SAndroid Build Coastguard Worker 
1092*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&out, CURL_X509_STR_MAX);
1093*6236dae4SAndroid Build Coastguard Worker   /* Prepare the certificate information for curl_easy_getinfo(). */
1094*6236dae4SAndroid Build Coastguard Worker 
1095*6236dae4SAndroid Build Coastguard Worker   /* Extract the certificate ASN.1 elements. */
1096*6236dae4SAndroid Build Coastguard Worker   if(Curl_parseX509(&cert, beg, end))
1097*6236dae4SAndroid Build Coastguard Worker     return CURLE_PEER_FAILED_VERIFICATION;
1098*6236dae4SAndroid Build Coastguard Worker 
1099*6236dae4SAndroid Build Coastguard Worker   /* Subject. */
1100*6236dae4SAndroid Build Coastguard Worker   result = DNtostr(&out, &cert.subject);
1101*6236dae4SAndroid Build Coastguard Worker   if(result)
1102*6236dae4SAndroid Build Coastguard Worker     goto done;
1103*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1104*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Subject", &out);
1105*6236dae4SAndroid Build Coastguard Worker     if(result)
1106*6236dae4SAndroid Build Coastguard Worker       goto done;
1107*6236dae4SAndroid Build Coastguard Worker   }
1108*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1109*6236dae4SAndroid Build Coastguard Worker 
1110*6236dae4SAndroid Build Coastguard Worker   /* Issuer. */
1111*6236dae4SAndroid Build Coastguard Worker   result = DNtostr(&out, &cert.issuer);
1112*6236dae4SAndroid Build Coastguard Worker   if(result)
1113*6236dae4SAndroid Build Coastguard Worker     goto done;
1114*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1115*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Issuer", &out);
1116*6236dae4SAndroid Build Coastguard Worker     if(result)
1117*6236dae4SAndroid Build Coastguard Worker       goto done;
1118*6236dae4SAndroid Build Coastguard Worker   }
1119*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1120*6236dae4SAndroid Build Coastguard Worker 
1121*6236dae4SAndroid Build Coastguard Worker   /* Version (always fits in less than 32 bits). */
1122*6236dae4SAndroid Build Coastguard Worker   version = 0;
1123*6236dae4SAndroid Build Coastguard Worker   for(ptr = cert.version.beg; ptr < cert.version.end; ptr++)
1124*6236dae4SAndroid Build Coastguard Worker     version = (version << 8) | *(const unsigned char *) ptr;
1125*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1126*6236dae4SAndroid Build Coastguard Worker     result = Curl_dyn_addf(&out, "%x", version);
1127*6236dae4SAndroid Build Coastguard Worker     if(result)
1128*6236dae4SAndroid Build Coastguard Worker       goto done;
1129*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Version", &out);
1130*6236dae4SAndroid Build Coastguard Worker     if(result)
1131*6236dae4SAndroid Build Coastguard Worker       goto done;
1132*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_reset(&out);
1133*6236dae4SAndroid Build Coastguard Worker   }
1134*6236dae4SAndroid Build Coastguard Worker 
1135*6236dae4SAndroid Build Coastguard Worker   /* Serial number. */
1136*6236dae4SAndroid Build Coastguard Worker   result = ASN1tostr(&out, &cert.serialNumber, 0);
1137*6236dae4SAndroid Build Coastguard Worker   if(result)
1138*6236dae4SAndroid Build Coastguard Worker     goto done;
1139*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1140*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Serial Number", &out);
1141*6236dae4SAndroid Build Coastguard Worker     if(result)
1142*6236dae4SAndroid Build Coastguard Worker       goto done;
1143*6236dae4SAndroid Build Coastguard Worker   }
1144*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1145*6236dae4SAndroid Build Coastguard Worker 
1146*6236dae4SAndroid Build Coastguard Worker   /* Signature algorithm .*/
1147*6236dae4SAndroid Build Coastguard Worker   result = dumpAlgo(&out, &param, cert.signatureAlgorithm.beg,
1148*6236dae4SAndroid Build Coastguard Worker                     cert.signatureAlgorithm.end);
1149*6236dae4SAndroid Build Coastguard Worker   if(result)
1150*6236dae4SAndroid Build Coastguard Worker     goto done;
1151*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1152*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Signature Algorithm",
1153*6236dae4SAndroid Build Coastguard Worker                                    &out);
1154*6236dae4SAndroid Build Coastguard Worker     if(result)
1155*6236dae4SAndroid Build Coastguard Worker       goto done;
1156*6236dae4SAndroid Build Coastguard Worker   }
1157*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1158*6236dae4SAndroid Build Coastguard Worker 
1159*6236dae4SAndroid Build Coastguard Worker   /* Start Date. */
1160*6236dae4SAndroid Build Coastguard Worker   result = ASN1tostr(&out, &cert.notBefore, 0);
1161*6236dae4SAndroid Build Coastguard Worker   if(result)
1162*6236dae4SAndroid Build Coastguard Worker     goto done;
1163*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1164*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Start Date", &out);
1165*6236dae4SAndroid Build Coastguard Worker     if(result)
1166*6236dae4SAndroid Build Coastguard Worker       goto done;
1167*6236dae4SAndroid Build Coastguard Worker   }
1168*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1169*6236dae4SAndroid Build Coastguard Worker 
1170*6236dae4SAndroid Build Coastguard Worker   /* Expire Date. */
1171*6236dae4SAndroid Build Coastguard Worker   result = ASN1tostr(&out, &cert.notAfter, 0);
1172*6236dae4SAndroid Build Coastguard Worker   if(result)
1173*6236dae4SAndroid Build Coastguard Worker     goto done;
1174*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1175*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Expire Date", &out);
1176*6236dae4SAndroid Build Coastguard Worker     if(result)
1177*6236dae4SAndroid Build Coastguard Worker       goto done;
1178*6236dae4SAndroid Build Coastguard Worker   }
1179*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1180*6236dae4SAndroid Build Coastguard Worker 
1181*6236dae4SAndroid Build Coastguard Worker   /* Public Key Algorithm. */
1182*6236dae4SAndroid Build Coastguard Worker   result = dumpAlgo(&out, &param, cert.subjectPublicKeyAlgorithm.beg,
1183*6236dae4SAndroid Build Coastguard Worker                     cert.subjectPublicKeyAlgorithm.end);
1184*6236dae4SAndroid Build Coastguard Worker   if(result)
1185*6236dae4SAndroid Build Coastguard Worker     goto done;
1186*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1187*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Public Key Algorithm",
1188*6236dae4SAndroid Build Coastguard Worker                                    &out);
1189*6236dae4SAndroid Build Coastguard Worker     if(result)
1190*6236dae4SAndroid Build Coastguard Worker       goto done;
1191*6236dae4SAndroid Build Coastguard Worker   }
1192*6236dae4SAndroid Build Coastguard Worker 
1193*6236dae4SAndroid Build Coastguard Worker   rc = do_pubkey(data, certnum, Curl_dyn_ptr(&out),
1194*6236dae4SAndroid Build Coastguard Worker                  &param, &cert.subjectPublicKey);
1195*6236dae4SAndroid Build Coastguard Worker   if(rc) {
1196*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OUT_OF_MEMORY; /* the most likely error */
1197*6236dae4SAndroid Build Coastguard Worker     goto done;
1198*6236dae4SAndroid Build Coastguard Worker   }
1199*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1200*6236dae4SAndroid Build Coastguard Worker 
1201*6236dae4SAndroid Build Coastguard Worker   /* Signature. */
1202*6236dae4SAndroid Build Coastguard Worker   result = ASN1tostr(&out, &cert.signature, 0);
1203*6236dae4SAndroid Build Coastguard Worker   if(result)
1204*6236dae4SAndroid Build Coastguard Worker     goto done;
1205*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo) {
1206*6236dae4SAndroid Build Coastguard Worker     result = ssl_push_certinfo_dyn(data, certnum, "Signature", &out);
1207*6236dae4SAndroid Build Coastguard Worker     if(result)
1208*6236dae4SAndroid Build Coastguard Worker       goto done;
1209*6236dae4SAndroid Build Coastguard Worker   }
1210*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1211*6236dae4SAndroid Build Coastguard Worker 
1212*6236dae4SAndroid Build Coastguard Worker   /* Generate PEM certificate. */
1213*6236dae4SAndroid Build Coastguard Worker   result = Curl_base64_encode(cert.certificate.beg,
1214*6236dae4SAndroid Build Coastguard Worker                               cert.certificate.end - cert.certificate.beg,
1215*6236dae4SAndroid Build Coastguard Worker                               &certptr, &clen);
1216*6236dae4SAndroid Build Coastguard Worker   if(result)
1217*6236dae4SAndroid Build Coastguard Worker     goto done;
1218*6236dae4SAndroid Build Coastguard Worker 
1219*6236dae4SAndroid Build Coastguard Worker   /* Generate the final output certificate string. Format is:
1220*6236dae4SAndroid Build Coastguard Worker      -----BEGIN CERTIFICATE-----\n
1221*6236dae4SAndroid Build Coastguard Worker      <max 64 base64 characters>\n
1222*6236dae4SAndroid Build Coastguard Worker      .
1223*6236dae4SAndroid Build Coastguard Worker      .
1224*6236dae4SAndroid Build Coastguard Worker      .
1225*6236dae4SAndroid Build Coastguard Worker      -----END CERTIFICATE-----\n
1226*6236dae4SAndroid Build Coastguard Worker    */
1227*6236dae4SAndroid Build Coastguard Worker 
1228*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_reset(&out);
1229*6236dae4SAndroid Build Coastguard Worker 
1230*6236dae4SAndroid Build Coastguard Worker   /* Build the certificate string. */
1231*6236dae4SAndroid Build Coastguard Worker   result = Curl_dyn_add(&out, "-----BEGIN CERTIFICATE-----\n");
1232*6236dae4SAndroid Build Coastguard Worker   if(!result) {
1233*6236dae4SAndroid Build Coastguard Worker     size_t j = 0;
1234*6236dae4SAndroid Build Coastguard Worker 
1235*6236dae4SAndroid Build Coastguard Worker     while(!result && (j < clen)) {
1236*6236dae4SAndroid Build Coastguard Worker       size_t chunksize = (clen - j) > 64 ? 64 : (clen - j);
1237*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(&out, &certptr[j], chunksize);
1238*6236dae4SAndroid Build Coastguard Worker       if(!result)
1239*6236dae4SAndroid Build Coastguard Worker         result = Curl_dyn_addn(&out, "\n", 1);
1240*6236dae4SAndroid Build Coastguard Worker       j += chunksize;
1241*6236dae4SAndroid Build Coastguard Worker     }
1242*6236dae4SAndroid Build Coastguard Worker     if(!result)
1243*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_add(&out, "-----END CERTIFICATE-----\n");
1244*6236dae4SAndroid Build Coastguard Worker   }
1245*6236dae4SAndroid Build Coastguard Worker   free(certptr);
1246*6236dae4SAndroid Build Coastguard Worker   if(!result)
1247*6236dae4SAndroid Build Coastguard Worker     if(data->set.ssl.certinfo)
1248*6236dae4SAndroid Build Coastguard Worker       result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out);
1249*6236dae4SAndroid Build Coastguard Worker 
1250*6236dae4SAndroid Build Coastguard Worker done:
1251*6236dae4SAndroid Build Coastguard Worker   if(result)
1252*6236dae4SAndroid Build Coastguard Worker     failf(data, "Failed extracting certificate chain");
1253*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&out);
1254*6236dae4SAndroid Build Coastguard Worker   return result;
1255*6236dae4SAndroid Build Coastguard Worker }
1256*6236dae4SAndroid Build Coastguard Worker 
1257*6236dae4SAndroid Build Coastguard Worker #endif /* WANT_EXTRACT_CERTINFO */
1258*6236dae4SAndroid Build Coastguard Worker 
1259*6236dae4SAndroid Build Coastguard Worker #endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
1260