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