Treat caCertificate as pem contents rather than pem filename
[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
38 #ifdef HAVE_MOONSHOT_GET_IDENTITY
39 #include <libmoonshot.h>
40
41 static OM_uint32
42 libMoonshotMapError(OM_uint32 *minor,
43                     MoonshotError **pError)
44 {
45     MoonshotError *error = *pError;
46
47     GSSEAP_ASSERT(error != NULL);
48
49     switch (error->code) {
50     case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE:
51         *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE;
52         break;
53     case MOONSHOT_ERROR_NO_IDENTITY_SELECTED:
54         *minor = GSSEAP_NO_IDENTITY_SELECTED;
55         break;
56     case MOONSHOT_ERROR_INSTALLATION_ERROR:
57         *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR;
58         break;
59     case MOONSHOT_ERROR_OS_ERROR:
60         *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR;
61         break;
62     case MOONSHOT_ERROR_IPC_ERROR:
63         *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR;
64         break;
65     default:
66         *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR;
67         break;
68     }
69
70     gssEapSaveStatusInfo(*minor, error->message);
71     moonshot_error_free(error);
72     *pError = NULL;
73
74     return GSS_S_CRED_UNAVAIL;
75 }
76
77 OM_uint32
78 libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
79                                   const gss_cred_id_t cred,
80                                   gss_name_t *pName)
81 {
82     OM_uint32 major, tmpMinor;
83     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
84     gss_name_t name = GSS_C_NO_NAME;
85     gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
86     char *nai = NULL;
87     char *password = NULL;
88     char *serverCertificateHash = NULL;
89     char *caCertificate = NULL;
90     char *subjectNameConstraint = NULL;
91     char *subjectAltNameConstraint = NULL;
92     MoonshotError *error = NULL;
93
94     *pName = GSS_C_NO_NAME;
95
96     if (!moonshot_get_default_identity(&nai,
97                                        &password,
98                                        &serverCertificateHash,
99                                        &caCertificate,
100                                        &subjectNameConstraint,
101                                        &subjectAltNameConstraint,
102                                        &error)) {
103         if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) {
104             major = GSS_S_CRED_UNAVAIL;
105             *minor = GSSEAP_NO_DEFAULT_IDENTITY;
106             moonshot_error_free(error);
107         } else
108             major = libMoonshotMapError(minor, &error);
109         goto cleanup;
110     }
111
112     tmpBuffer.value = nai;
113     tmpBuffer.length = strlen(nai);
114
115     major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name);
116     if (GSS_ERROR(major))
117         goto cleanup;
118
119     *pName = name;
120     name = GSS_C_NO_NAME;
121
122 cleanup:
123     moonshot_free(nai);
124     moonshot_free(password);
125     moonshot_free(serverCertificateHash);
126     moonshot_free(caCertificate);
127     moonshot_free(subjectNameConstraint);
128     moonshot_free(subjectAltNameConstraint);
129
130     gssEapReleaseName(&tmpMinor, &name);
131
132     return major;
133 }
134
135 static int stringEmpty(const char * s)
136 {
137     if (s == NULL)
138       return 1;
139     if (strlen(s) > 0)
140         return 0;
141     return 1;
142 }
143
144 OM_uint32
145 libMoonshotResolveInitiatorCred(OM_uint32 *minor,
146                                 gss_cred_id_t cred,
147                                 const gss_name_t targetName)
148 {
149     OM_uint32 major, tmpMinor;
150     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
151     gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER;
152     gss_buffer_desc target = GSS_C_EMPTY_BUFFER;
153     gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
154     char *nai = NULL;
155     char *password = NULL;
156     char *serverCertificateHash = NULL;
157     char *caCertificate = NULL;
158     char *subjectNameConstraint = NULL;
159     char *subjectAltNameConstraint = NULL;
160     MoonshotError *error = NULL;
161     BIO *bio = NULL;
162
163     if (cred->name != GSS_C_NO_NAME) {
164         major = gssEapDisplayName(minor, cred->name, &initiator, NULL);
165         if (GSS_ERROR(major))
166             goto cleanup;
167     }
168
169     if (targetName != GSS_C_NO_NAME) {
170         major = gssEapDisplayName(minor, targetName, &target, NULL);
171         if (GSS_ERROR(major))
172             goto cleanup;
173     }
174
175     if (!moonshot_get_identity((const char *)initiator.value,
176                                (const char *)cred->password.value,
177                                (const char *)target.value,
178                                &nai,
179                                &password,
180                                &serverCertificateHash,
181                                &caCertificate,
182                                &subjectNameConstraint,
183                                &subjectAltNameConstraint,
184                                &error)) {
185         major = libMoonshotMapError(minor, &error);
186         goto cleanup;
187     }
188
189     gssEapReleaseName(&tmpMinor, &cred->name);
190
191     tmpBuffer.value = nai;
192     tmpBuffer.length = strlen(nai);
193
194     major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME,
195                              nameMech, &cred->name);
196     if (GSS_ERROR(major))
197         goto cleanup;
198
199     tmpBuffer.value = password;
200     tmpBuffer.length = strlen(password);
201
202     major = gssEapSetCredPassword(minor, cred, &tmpBuffer);
203     if (GSS_ERROR(major))
204         goto cleanup;
205
206     gss_release_buffer(&tmpMinor, &cred->caCertificate);
207     gss_release_buffer(&tmpMinor, &cred->caCertificateBlob);
208     gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
209     gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
210
211     if (!stringEmpty(serverCertificateHash)) {
212         size_t len = strlen(serverCertificateHash);
213
214         #define HASH_PREFIX             "hash://server/sha256/"
215         #define HASH_PREFIX_LEN         (sizeof(HASH_PREFIX) - 1)
216
217         cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1);
218         if (cred->caCertificate.value == NULL) {
219             major = GSS_S_FAILURE;
220             *minor = ENOMEM;
221             goto cleanup;
222         }
223
224         memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN);
225         memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len);
226
227         ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0';
228
229         cred->caCertificate.length = HASH_PREFIX_LEN + len;
230     } else if (!stringEmpty(caCertificate)) {
231         BUF_MEM *bptr;
232         X509 *cert;
233         gss_buffer_desc tmp;
234
235         bio = BIO_new_mem_buf(caCertificate, -1);
236         if (bio == NULL) {
237             major = GSS_S_FAILURE;
238             *minor = ENOMEM;
239             goto cleanup;
240         }
241         cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
242         if (cert == NULL) {
243             major = GSS_S_FAILURE;
244             *minor = ENOMEM;
245             goto cleanup;
246         }
247         BIO_free(bio);
248         bio = BIO_new(BIO_s_mem());
249         if (i2d_X509_bio(bio, cert) < 0) {
250             major = GSS_S_FAILURE;
251             *minor = ENOMEM; /* TODO */
252             goto cleanup;
253         }
254         BIO_get_mem_ptr(bio, &bptr);
255         tmp.value = bptr->data;
256         tmp.length = bptr->length;
257         major = duplicateBuffer(minor, &tmp, &cred->caCertificateBlob);
258         if (major != GSS_S_COMPLETE) {
259             goto cleanup;
260         }
261         BIO_free(bio);
262         makeStringBufferOrCleanup("blob://ca-cert", &cred->caCertificate);
263     }
264
265     if (!stringEmpty(subjectNameConstraint))
266         makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint);
267     if (!stringEmpty(subjectAltNameConstraint))
268         makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint);
269
270 cleanup:
271     moonshot_free(nai);
272     moonshot_free(password);
273     moonshot_free(serverCertificateHash);
274     moonshot_free(caCertificate);
275     moonshot_free(subjectNameConstraint);
276     moonshot_free(subjectAltNameConstraint);
277     BIO_free(bio);
278
279     gss_release_buffer(&tmpMinor, &initiator);
280     gss_release_buffer(&tmpMinor, &target);
281
282     return major;
283 }
284 #endif /* HAVE_MOONSHOT_GET_IDENTITY */