xref: /curl/tests/libtest/lib3102.c (revision 25cbc2f7)
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  */
is_chain_in_order(struct curl_certinfo * cert_info)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       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 
wrfu(void * ptr,size_t size,size_t nmemb,void * stream)84 static 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 
test(char * URL)91 CURLcode 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 
134 test_cleanup:
135 
136   /* always cleanup */
137   curl_easy_cleanup(curl);
138   curl_global_cleanup();
139 
140   return res;
141 }
142