ip: Replace Sematics for Interface IP addresses
[vpp.git] / src / plugins / quic / certs.c
1 /*
2  * Copyright (c) 2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <openssl/pem.h>
17
18 #include <vppinfra/error.h>
19
20 #include <quic/certs.h>
21
22
23 int
24 ptls_compare_separator_line (const char *line, const char *begin_or_end,
25                              const char *label)
26 {
27   int ret = strncmp (line, "-----", 5);
28   size_t text_index = 5;
29
30   if (ret == 0)
31     {
32       size_t begin_or_end_length = strlen (begin_or_end);
33       ret = strncmp (line + text_index, begin_or_end, begin_or_end_length);
34       text_index += begin_or_end_length;
35     }
36
37   if (ret == 0)
38     {
39       ret = line[text_index] - ' ';
40       text_index++;
41     }
42
43   if (ret == 0)
44     {
45       size_t label_length = strlen (label);
46       ret = strncmp (line + text_index, label, label_length);
47       text_index += label_length;
48     }
49
50   if (ret == 0)
51     {
52       ret = strncmp (line + text_index, "-----", 5);
53     }
54
55   return ret;
56 }
57
58 int
59 ptls_get_bio_pem_object (BIO * bio, const char *label, ptls_buffer_t * buf)
60 {
61   int ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
62   char line[256];
63   ptls_base64_decode_state_t state;
64
65   /* Get the label on a line by itself */
66   while (BIO_gets (bio, line, 256))
67     {
68       if (ptls_compare_separator_line (line, "BEGIN", label) == 0)
69         {
70           ret = 0;
71           ptls_base64_decode_init (&state);
72           break;
73         }
74     }
75   /* Get the data in the buffer */
76   while (ret == 0 && BIO_gets (bio, line, 256))
77     {
78       if (ptls_compare_separator_line (line, "END", label) == 0)
79         {
80           if (state.status == PTLS_BASE64_DECODE_DONE
81               || (state.status == PTLS_BASE64_DECODE_IN_PROGRESS
82                   && state.nbc == 0))
83             {
84               ret = 0;
85             }
86           else
87             {
88               ret = PTLS_ERROR_INCORRECT_BASE64;
89             }
90           break;
91         }
92       else
93         {
94           ret = ptls_base64_decode (line, &state, buf);
95         }
96     }
97
98   return ret;
99 }
100
101 int
102 ptls_load_bio_pem_objects (BIO * bio, const char *label, ptls_iovec_t * list,
103                            size_t list_max, size_t * nb_objects)
104 {
105   int ret = 0;
106   size_t count = 0;
107
108   *nb_objects = 0;
109
110   if (ret == 0)
111     {
112       while (count < list_max)
113         {
114           ptls_buffer_t buf;
115
116           ptls_buffer_init (&buf, "", 0);
117
118           ret = ptls_get_bio_pem_object (bio, label, &buf);
119
120           if (ret == 0)
121             {
122               if (buf.off > 0 && buf.is_allocated)
123                 {
124                   list[count].base = buf.base;
125                   list[count].len = buf.off;
126                   count++;
127                 }
128               else
129                 {
130                   ptls_buffer_dispose (&buf);
131                 }
132             }
133           else
134             {
135               ptls_buffer_dispose (&buf);
136               break;
137             }
138         }
139     }
140
141   if (ret == PTLS_ERROR_PEM_LABEL_NOT_FOUND && count > 0)
142     {
143       ret = 0;
144     }
145
146   *nb_objects = count;
147
148   return ret;
149 }
150
151 #define PTLS_MAX_CERTS_IN_CONTEXT 16
152
153 int
154 ptls_load_bio_certificates (ptls_context_t * ctx, BIO * bio)
155 {
156   int ret = 0;
157
158   ctx->certificates.list =
159     (ptls_iovec_t *) malloc (PTLS_MAX_CERTS_IN_CONTEXT *
160                              sizeof (ptls_iovec_t));
161
162   if (ctx->certificates.list == NULL)
163     {
164       ret = PTLS_ERROR_NO_MEMORY;
165     }
166   else
167     {
168       ret =
169         ptls_load_bio_pem_objects (bio, "CERTIFICATE", ctx->certificates.list,
170                                    PTLS_MAX_CERTS_IN_CONTEXT,
171                                    &ctx->certificates.count);
172     }
173
174   return ret;
175 }
176
177 int
178 load_bio_certificate_chain (ptls_context_t * ctx, const char *cert_data)
179 {
180   BIO *cert_bio;
181   cert_bio = BIO_new_mem_buf (cert_data, -1);
182   if (ptls_load_bio_certificates (ctx, cert_bio) != 0)
183     {
184       BIO_free (cert_bio);
185       return -1;
186     }
187   BIO_free (cert_bio);
188   return 0;
189 }
190
191 int
192 load_bio_private_key (ptls_context_t * ctx, const char *pk_data)
193 {
194   static ptls_openssl_sign_certificate_t sc;
195   EVP_PKEY *pkey;
196   BIO *key_bio;
197
198   key_bio = BIO_new_mem_buf (pk_data, -1);
199   pkey = PEM_read_bio_PrivateKey (key_bio, NULL, NULL, NULL);
200   BIO_free (key_bio);
201
202   if (pkey == NULL)
203     return -1;
204
205   ptls_openssl_init_sign_certificate (&sc, pkey);
206   EVP_PKEY_free (pkey);
207
208   ctx->sign_certificate = &sc.super;
209   return 0;
210 }