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 "test.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 */ 32static 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 const char issuer_prefix[] = "Issuer:"; 50 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 printf("cert %d\n", cert); 62 printf(" subject: %s\n", subject); 63 printf(" 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 fprintf(stderr, "cert %d issuer does not match cert %d subject\n", 70 cert - 1, cert); 71 fprintf(stderr, "certificate chain is not in order\n"); 72 return false; 73 } 74 } 75 } 76 77 last_issuer = issuer; 78 } 79 80 printf("certificate chain is in order\n"); 81 return true; 82} 83 84static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) 85{ 86 (void)stream; 87 (void)ptr; 88 return size * nmemb; 89} 90 91int test(char *URL) 92{ 93 CURL *curl; 94 CURLcode res = CURLE_OK; 95 96 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 97 fprintf(stderr, "curl_global_init() failed\n"); 98 return TEST_ERR_MAJOR_BAD; 99 } 100 101 curl = curl_easy_init(); 102 if(!curl) { 103 fprintf(stderr, "curl_easy_init() failed\n"); 104 curl_global_cleanup(); 105 return TEST_ERR_MAJOR_BAD; 106 } 107 108 /* Set the HTTPS url to retrieve. */ 109 test_setopt(curl, CURLOPT_URL, URL); 110 111 /* Capture certificate information */ 112 test_setopt(curl, CURLOPT_CERTINFO, 1L); 113 114 /* Ignore output */ 115 test_setopt(curl, CURLOPT_WRITEFUNCTION, wrfu); 116 117 /* No peer verify */ 118 test_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 119 test_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 120 121 /* Perform the request, res will get the return code */ 122 res = curl_easy_perform(curl); 123 if(!res || res == CURLE_GOT_NOTHING) { 124 struct curl_certinfo *cert_info = NULL; 125 /* Get the certificate information */ 126 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_info); 127 if(!res) { 128 /* Check to see if the certificate chain is ordered correctly */ 129 if(!is_chain_in_order(cert_info)) 130 res = TEST_ERR_FAILURE; 131 } 132 } 133 134test_cleanup: 135 136 /* always cleanup */ 137 curl_easy_cleanup(curl); 138 curl_global_cleanup(); 139 140 return res; 141} 142