lib3102.c (4367B)
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 "first.h" 25 26 #include "memdebug.h" 27 28 /* 29 * Verify correct order of certificates in the chain by comparing the 30 * subject and issuer attributes of each certificate. 31 */ 32 static bool is_chain_in_order(struct curl_certinfo *cert_info) 33 { 34 char *last_issuer = NULL; 35 int cert; 36 37 /* Chains with only a single certificate are always in order */ 38 if(cert_info->num_of_certs <= 1) 39 return 1; 40 41 /* Enumerate each certificate in the chain */ 42 for(cert = 0; cert < cert_info->num_of_certs; cert++) { 43 struct curl_slist *slist = cert_info->certinfo[cert]; 44 char *issuer = NULL; 45 char *subject = NULL; 46 47 /* Find the certificate issuer and subject by enumerating each field */ 48 for(; slist && (!issuer || !subject); slist = slist->next) { 49 static const char issuer_prefix[] = "Issuer:"; 50 static const char subject_prefix[] = "Subject:"; 51 52 if(!strncmp(slist->data, issuer_prefix, sizeof(issuer_prefix)-1)) { 53 issuer = slist->data + sizeof(issuer_prefix)-1; 54 } 55 if(!strncmp(slist->data, subject_prefix, sizeof(subject_prefix)-1)) { 56 subject = slist->data + sizeof(subject_prefix)-1; 57 } 58 } 59 60 if(subject && issuer) { 61 curl_mprintf("cert %d\n", cert); 62 curl_mprintf(" subject: %s\n", subject); 63 curl_mprintf(" issuer: %s\n", issuer); 64 65 if(last_issuer) { 66 /* If the last certificate's issuer matches the current certificate's 67 * subject, then the chain is in order */ 68 if(strcmp(last_issuer, subject) != 0) { 69 curl_mfprintf(stderr, 70 "cert %d issuer does not match cert %d subject\n", 71 cert - 1, cert); 72 curl_mfprintf(stderr, "certificate chain is not in order\n"); 73 return false; 74 } 75 } 76 } 77 78 last_issuer = issuer; 79 } 80 81 curl_mprintf("certificate chain is in order\n"); 82 return true; 83 } 84 85 static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) 86 { 87 (void)stream; 88 (void)ptr; 89 return size * nmemb; 90 } 91 92 static CURLcode test_lib3102(char *URL) 93 { 94 CURL *curl; 95 CURLcode res = CURLE_OK; 96 97 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 98 curl_mfprintf(stderr, "curl_global_init() failed\n"); 99 return TEST_ERR_MAJOR_BAD; 100 } 101 102 curl = curl_easy_init(); 103 if(!curl) { 104 curl_mfprintf(stderr, "curl_easy_init() failed\n"); 105 curl_global_cleanup(); 106 return TEST_ERR_MAJOR_BAD; 107 } 108 109 /* Set the HTTPS url to retrieve. */ 110 test_setopt(curl, CURLOPT_URL, URL); 111 112 /* Capture certificate information */ 113 test_setopt(curl, CURLOPT_CERTINFO, 1L); 114 115 /* Ignore output */ 116 test_setopt(curl, CURLOPT_WRITEFUNCTION, wrfu); 117 118 /* No peer verify */ 119 test_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 120 test_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 121 122 /* Perform the request, res will get the return code */ 123 res = curl_easy_perform(curl); 124 if(!res || res == CURLE_GOT_NOTHING) { 125 struct curl_certinfo *cert_info = NULL; 126 /* Get the certificate information */ 127 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_info); 128 if(!res) { 129 /* Check to see if the certificate chain is ordered correctly */ 130 if(!is_chain_in_order(cert_info)) 131 res = TEST_ERR_FAILURE; 132 } 133 } 134 135 test_cleanup: 136 137 /* always cleanup */ 138 curl_easy_cleanup(curl); 139 curl_global_cleanup(); 140 141 return res; 142 }