x509asn1.c 34 KB

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