x509asn1.c 33 KB

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