Avoid double-free of bio. Better error code for ca cert parsing failure.
[mech_eap.git] / mech_eap / util_moonshot.c
1 /*
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include "gssapiP_eap.h"
34 #include <openssl/bio.h>
35 #include <openssl/pem.h>
36 #include <openssl/x509.h>
37 #include <stdio.h>
38
39 #ifdef HAVE_MOONSHOT_GET_IDENTITY
40 #include <libmoonshot.h>
41
42 static OM_uint32
43 libMoonshotMapError(OM_uint32 *minor,
44                     MoonshotError **pError)
45 {
46     MoonshotError *error = *pError;
47
48     GSSEAP_ASSERT(error != NULL);
49
50     switch (error->code) {
51     case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE:
52         *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE;
53         break;
54     case MOONSHOT_ERROR_NO_IDENTITY_SELECTED:
55         *minor = GSSEAP_NO_IDENTITY_SELECTED;
56         break;
57     case MOONSHOT_ERROR_INSTALLATION_ERROR:
58         *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR;
59         break;
60     case MOONSHOT_ERROR_OS_ERROR:
61         *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR;
62         break;
63     case MOONSHOT_ERROR_IPC_ERROR:
64         *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR;
65         break;
66     default:
67         *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR;
68         break;
69     }
70
71     gssEapSaveStatusInfo(*minor, error->message);
72     moonshot_error_free(error);
73     *pError = NULL;
74
75     return GSS_S_CRED_UNAVAIL;
76 }
77
78 OM_uint32
79 libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
80                                   const gss_cred_id_t cred,
81                                   gss_name_t *pName)
82 {
83     OM_uint32 major, tmpMinor;
84     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
85     gss_name_t name = GSS_C_NO_NAME;
86     gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
87     char *nai = NULL;
88     char *password = NULL;
89     char *serverCertificateHash = NULL;
90     char *caCertificate = NULL;
91     char *subjectNameConstraint = NULL;
92     char *subjectAltNameConstraint = NULL;
93     MoonshotError *error = NULL;
94
95     *pName = GSS_C_NO_NAME;
96
97     if (!moonshot_get_default_identity(&nai,
98                                        &password,
99                                        &serverCertificateHash,
100                                        &caCertificate,
101                                        &subjectNameConstraint,
102                                        &subjectAltNameConstraint,
103                                        &error)) {
104         if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) {
105             major = GSS_S_CRED_UNAVAIL;
106             *minor = GSSEAP_NO_DEFAULT_IDENTITY;
107             moonshot_error_free(error);
108         } else
109             major = libMoonshotMapError(minor, &error);
110         goto cleanup;
111     }
112
113     tmpBuffer.value = nai;
114     tmpBuffer.length = strlen(nai);
115
116     major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name);
117     if (GSS_ERROR(major))
118         goto cleanup;
119
120     *pName = name;
121     name = GSS_C_NO_NAME;
122
123 cleanup:
124     moonshot_free(nai);
125     moonshot_free(password);
126     moonshot_free(serverCertificateHash);
127     moonshot_free(caCertificate);
128     moonshot_free(subjectNameConstraint);
129     moonshot_free(subjectAltNameConstraint);
130
131     gssEapReleaseName(&tmpMinor, &name);
132
133     return major;
134 }
135
136 static int stringEmpty(const char * s)
137 {
138     if (s == NULL)
139       return 1;
140     if (strlen(s) > 0)
141         return 0;
142     return 1;
143 }
144
145 OM_uint32
146 libMoonshotResolveInitiatorCred(OM_uint32 *minor,
147                                 gss_cred_id_t cred,
148                                 const gss_name_t targetName)
149 {
150     OM_uint32 major, tmpMinor;
151     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
152     gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER;
153     gss_buffer_desc target = GSS_C_EMPTY_BUFFER;
154     gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
155     char *nai = NULL;
156     char *password = NULL;
157     char *serverCertificateHash = NULL;
158     char *caCertificate = NULL;
159     char *subjectNameConstraint = NULL;
160     char *subjectAltNameConstraint = NULL;
161     MoonshotError *error = NULL;
162     BIO *bio = NULL;
163
164     if (cred->name != GSS_C_NO_NAME) {
165         major = gssEapDisplayName(minor, cred->name, &initiator, NULL);
166         if (GSS_ERROR(major))
167             goto cleanup;
168     }
169
170     if (targetName != GSS_C_NO_NAME) {
171         major = gssEapDisplayName(minor, targetName, &target, NULL);
172         if (GSS_ERROR(major))
173             goto cleanup;
174     }
175
176     if (!moonshot_get_identity((const char *)initiator.value,
177                                (const char *)cred->password.value,
178                                (const char *)target.value,
179                                &nai,
180                                &password,
181                                &serverCertificateHash,
182                                &caCertificate,
183                                &subjectNameConstraint,
184                                &subjectAltNameConstraint,
185                                &error)) {
186         major = libMoonshotMapError(minor, &error);
187         goto cleanup;
188     }
189
190     gssEapReleaseName(&tmpMinor, &cred->name);
191
192     tmpBuffer.value = nai;
193     tmpBuffer.length = strlen(nai);
194
195     major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME,
196                              nameMech, &cred->name);
197     if (GSS_ERROR(major))
198         goto cleanup;
199
200     tmpBuffer.value = password;
201     tmpBuffer.length = strlen(password);
202
203     major = gssEapSetCredPassword(minor, cred, &tmpBuffer);
204     if (GSS_ERROR(major))
205         goto cleanup;
206
207     gss_release_buffer(&tmpMinor, &cred->caCertificate);
208     gss_release_buffer(&tmpMinor, &cred->caCertificateBlob);
209     gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
210     gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
211
212     if (!stringEmpty(serverCertificateHash)) {
213         size_t len = strlen(serverCertificateHash);
214
215         #define HASH_PREFIX             "hash://server/sha256/"
216         #define HASH_PREFIX_LEN         (sizeof(HASH_PREFIX) - 1)
217
218         cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1);
219         if (cred->caCertificate.value == NULL) {
220             major = GSS_S_FAILURE;
221             *minor = ENOMEM;
222             goto cleanup;
223         }
224
225         memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN);
226         memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len);
227
228         ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0';
229
230         cred->caCertificate.length = HASH_PREFIX_LEN + len;
231     } else if (!stringEmpty(caCertificate)) {
232         BUF_MEM *bptr;
233         X509 *cert;
234         gss_buffer_desc tmp;
235
236         bio = BIO_new_mem_buf(caCertificate, -1);
237         if (bio == NULL) {
238             major = GSS_S_FAILURE;
239             *minor = ENOMEM;
240             goto cleanup;
241         }
242         cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
243         if (cert == NULL) {
244             major = GSS_S_DEFECTIVE_CREDENTIAL;
245             *minor = GSSEAP_BAD_CACERTIFICATE;
246             goto cleanup;
247         }
248         BIO_free(bio);
249         bio = BIO_new(BIO_s_mem());
250         if (i2d_X509_bio(bio, cert) < 0) {
251             major = GSS_S_DEFECTIVE_CREDENTIAL;
252             *minor = GSSEAP_BAD_CACERTIFICATE;
253             goto cleanup;
254         }
255         BIO_get_mem_ptr(bio, &bptr);
256         tmp.value = bptr->data;
257         tmp.length = bptr->length;
258         major = duplicateBuffer(minor, &tmp, &cred->caCertificateBlob);
259         if (major != GSS_S_COMPLETE) {
260             goto cleanup;
261         }
262         BIO_free(bio);
263         bio = NULL;
264         makeStringBufferOrCleanup("blob://ca-cert", &cred->caCertificate);
265     }
266
267     if (!stringEmpty(subjectNameConstraint))
268         makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint);
269     if (!stringEmpty(subjectAltNameConstraint))
270         makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint);
271
272 cleanup:
273     moonshot_free(nai);
274     moonshot_free(password);
275     moonshot_free(serverCertificateHash);
276     moonshot_free(caCertificate);
277     moonshot_free(subjectNameConstraint);
278     moonshot_free(subjectAltNameConstraint);
279     BIO_free(bio);
280
281     gss_release_buffer(&tmpMinor, &initiator);
282     gss_release_buffer(&tmpMinor, &target);
283
284     return major;
285 }
286 #endif /* HAVE_MOONSHOT_GET_IDENTITY */