xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_saslname.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* lib/gssapi/mechglue/g_saslname.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright (C) 2010 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert  * All rights reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert #include "mglueP.h"
28*7f2fe78bSCy Schubert #include <krb5/krb5.h>
29*7f2fe78bSCy Schubert 
30*7f2fe78bSCy Schubert static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
31*7f2fe78bSCy Schubert 
32*7f2fe78bSCy Schubert #define OID_SASL_NAME_LENGTH  (sizeof("GS2-XXXXXXXXXXX") - 1)
33*7f2fe78bSCy Schubert 
34*7f2fe78bSCy Schubert static OM_uint32
oidToSaslName(OM_uint32 * minor,const gss_OID mech,char sasl_name[OID_SASL_NAME_LENGTH+1])35*7f2fe78bSCy Schubert oidToSaslName(OM_uint32 *minor, const gss_OID mech,
36*7f2fe78bSCy Schubert               char sasl_name[OID_SASL_NAME_LENGTH + 1])
37*7f2fe78bSCy Schubert {
38*7f2fe78bSCy Schubert     unsigned char derBuf[2];
39*7f2fe78bSCy Schubert     krb5_crypto_iov iov[3];
40*7f2fe78bSCy Schubert     unsigned char cksumBuf[20], *q = cksumBuf;
41*7f2fe78bSCy Schubert     char *p = sasl_name;
42*7f2fe78bSCy Schubert 
43*7f2fe78bSCy Schubert     if (mech->length > 127) {
44*7f2fe78bSCy Schubert         *minor = ERANGE;
45*7f2fe78bSCy Schubert         return GSS_S_BAD_MECH;
46*7f2fe78bSCy Schubert     }
47*7f2fe78bSCy Schubert 
48*7f2fe78bSCy Schubert     derBuf[0] = 0x06;
49*7f2fe78bSCy Schubert     derBuf[1] = (unsigned char)mech->length;
50*7f2fe78bSCy Schubert 
51*7f2fe78bSCy Schubert     iov[0].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
52*7f2fe78bSCy Schubert     iov[0].data.length = 2;
53*7f2fe78bSCy Schubert     iov[0].data.data = (char *)derBuf;
54*7f2fe78bSCy Schubert     iov[1].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
55*7f2fe78bSCy Schubert     iov[1].data.length = mech->length;
56*7f2fe78bSCy Schubert     iov[1].data.data = (char *)mech->elements;
57*7f2fe78bSCy Schubert     iov[2].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
58*7f2fe78bSCy Schubert     iov[2].data.length = sizeof(cksumBuf);
59*7f2fe78bSCy Schubert     iov[2].data.data = (char *)cksumBuf;
60*7f2fe78bSCy Schubert 
61*7f2fe78bSCy Schubert     *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_SHA1, NULL, 0, iov, 3);
62*7f2fe78bSCy Schubert     if (*minor != 0)
63*7f2fe78bSCy Schubert         return GSS_S_FAILURE;
64*7f2fe78bSCy Schubert 
65*7f2fe78bSCy Schubert     memcpy(p, "GS2-", 4);
66*7f2fe78bSCy Schubert     p += 4;
67*7f2fe78bSCy Schubert 
68*7f2fe78bSCy Schubert     *p++ = basis_32[q[0] >> 3];
69*7f2fe78bSCy Schubert     *p++ = basis_32[((q[0] & 7) << 2) | (q[1] >> 6)];
70*7f2fe78bSCy Schubert     *p++ = basis_32[(q[1] & 0x3f) >> 1];
71*7f2fe78bSCy Schubert     *p++ = basis_32[((q[1] & 1) << 4) | (q[2] >> 4)];
72*7f2fe78bSCy Schubert     *p++ = basis_32[((q[2] & 0xf) << 1) | (q[3] >> 7)];
73*7f2fe78bSCy Schubert     *p++ = basis_32[(q[3] & 0x7f) >> 2];
74*7f2fe78bSCy Schubert     *p++ = basis_32[((q[3] & 3) << 3) | (q[4] >> 5)];
75*7f2fe78bSCy Schubert     *p++ = basis_32[(q[4] & 0x1f)];
76*7f2fe78bSCy Schubert     *p++ = basis_32[q[5] >> 3];
77*7f2fe78bSCy Schubert     *p++ = basis_32[((q[5] & 7) << 2) | (q[6] >> 6)];
78*7f2fe78bSCy Schubert     *p++ = basis_32[(q[6] & 0x3f) >> 1];
79*7f2fe78bSCy Schubert 
80*7f2fe78bSCy Schubert     *p++ = '\0';
81*7f2fe78bSCy Schubert 
82*7f2fe78bSCy Schubert     *minor = 0;
83*7f2fe78bSCy Schubert     return GSS_S_COMPLETE;
84*7f2fe78bSCy Schubert }
85*7f2fe78bSCy Schubert 
86*7f2fe78bSCy Schubert static OM_uint32
oidToSaslNameAlloc(OM_uint32 * minor,const gss_OID mech,gss_buffer_t sasl_name)87*7f2fe78bSCy Schubert oidToSaslNameAlloc(OM_uint32 *minor, const gss_OID mech,
88*7f2fe78bSCy Schubert                    gss_buffer_t sasl_name)
89*7f2fe78bSCy Schubert {
90*7f2fe78bSCy Schubert     OM_uint32 status, tmpMinor;
91*7f2fe78bSCy Schubert 
92*7f2fe78bSCy Schubert     sasl_name->value = malloc(OID_SASL_NAME_LENGTH + 1);
93*7f2fe78bSCy Schubert     if (sasl_name->value == NULL) {
94*7f2fe78bSCy Schubert         *minor = ENOMEM;
95*7f2fe78bSCy Schubert         return GSS_S_FAILURE;
96*7f2fe78bSCy Schubert     }
97*7f2fe78bSCy Schubert     sasl_name->length = OID_SASL_NAME_LENGTH;
98*7f2fe78bSCy Schubert 
99*7f2fe78bSCy Schubert     status = oidToSaslName(minor, mech, (char *)sasl_name->value);
100*7f2fe78bSCy Schubert     if (GSS_ERROR(status)) {
101*7f2fe78bSCy Schubert         gss_release_buffer(&tmpMinor, sasl_name);
102*7f2fe78bSCy Schubert         return status;
103*7f2fe78bSCy Schubert     }
104*7f2fe78bSCy Schubert 
105*7f2fe78bSCy Schubert     return GSS_S_COMPLETE;
106*7f2fe78bSCy Schubert }
107*7f2fe78bSCy Schubert 
gss_inquire_saslname_for_mech(OM_uint32 * minor_status,const gss_OID desired_mech,gss_buffer_t sasl_mech_name,gss_buffer_t mech_name,gss_buffer_t mech_description)108*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV gss_inquire_saslname_for_mech(
109*7f2fe78bSCy Schubert     OM_uint32     *minor_status,
110*7f2fe78bSCy Schubert     const gss_OID  desired_mech,
111*7f2fe78bSCy Schubert     gss_buffer_t   sasl_mech_name,
112*7f2fe78bSCy Schubert     gss_buffer_t   mech_name,
113*7f2fe78bSCy Schubert     gss_buffer_t   mech_description)
114*7f2fe78bSCy Schubert {
115*7f2fe78bSCy Schubert     OM_uint32       status;
116*7f2fe78bSCy Schubert     gss_OID         selected_mech, public_mech;
117*7f2fe78bSCy Schubert     gss_mechanism   mech;
118*7f2fe78bSCy Schubert 
119*7f2fe78bSCy Schubert     if (minor_status == NULL)
120*7f2fe78bSCy Schubert         return GSS_S_CALL_INACCESSIBLE_WRITE;
121*7f2fe78bSCy Schubert 
122*7f2fe78bSCy Schubert     *minor_status = 0;
123*7f2fe78bSCy Schubert 
124*7f2fe78bSCy Schubert     if (sasl_mech_name != GSS_C_NO_BUFFER) {
125*7f2fe78bSCy Schubert         sasl_mech_name->length = 0;
126*7f2fe78bSCy Schubert         sasl_mech_name->value = NULL;
127*7f2fe78bSCy Schubert     }
128*7f2fe78bSCy Schubert 
129*7f2fe78bSCy Schubert     if (mech_name != GSS_C_NO_BUFFER) {
130*7f2fe78bSCy Schubert         mech_name->length = 0;
131*7f2fe78bSCy Schubert         mech_name->value = NULL;
132*7f2fe78bSCy Schubert     }
133*7f2fe78bSCy Schubert 
134*7f2fe78bSCy Schubert     if (mech_description != GSS_C_NO_BUFFER) {
135*7f2fe78bSCy Schubert         mech_description->length = 0;
136*7f2fe78bSCy Schubert         mech_description->value = NULL;
137*7f2fe78bSCy Schubert     }
138*7f2fe78bSCy Schubert 
139*7f2fe78bSCy Schubert     status = gssint_select_mech_type(minor_status, desired_mech,
140*7f2fe78bSCy Schubert                                      &selected_mech);
141*7f2fe78bSCy Schubert     if (status != GSS_S_COMPLETE)
142*7f2fe78bSCy Schubert         return status;
143*7f2fe78bSCy Schubert 
144*7f2fe78bSCy Schubert     mech = gssint_get_mechanism(desired_mech);
145*7f2fe78bSCy Schubert     if (mech == NULL) {
146*7f2fe78bSCy Schubert         return GSS_S_BAD_MECH;
147*7f2fe78bSCy Schubert     } else if (mech->gss_inquire_saslname_for_mech == NULL) {
148*7f2fe78bSCy Schubert         status = GSS_S_UNAVAILABLE;
149*7f2fe78bSCy Schubert     } else {
150*7f2fe78bSCy Schubert         public_mech = gssint_get_public_oid(selected_mech);
151*7f2fe78bSCy Schubert         status = mech->gss_inquire_saslname_for_mech(minor_status, public_mech,
152*7f2fe78bSCy Schubert                                                      sasl_mech_name, mech_name,
153*7f2fe78bSCy Schubert                                                      mech_description);
154*7f2fe78bSCy Schubert         if (status != GSS_S_COMPLETE)
155*7f2fe78bSCy Schubert             map_error(minor_status, mech);
156*7f2fe78bSCy Schubert     }
157*7f2fe78bSCy Schubert 
158*7f2fe78bSCy Schubert     if (status == GSS_S_UNAVAILABLE) {
159*7f2fe78bSCy Schubert         if (sasl_mech_name != GSS_C_NO_BUFFER)
160*7f2fe78bSCy Schubert             status = oidToSaslNameAlloc(minor_status, desired_mech,
161*7f2fe78bSCy Schubert                                         sasl_mech_name);
162*7f2fe78bSCy Schubert         else
163*7f2fe78bSCy Schubert             status = GSS_S_COMPLETE;
164*7f2fe78bSCy Schubert     }
165*7f2fe78bSCy Schubert 
166*7f2fe78bSCy Schubert     return status;
167*7f2fe78bSCy Schubert }
168*7f2fe78bSCy Schubert 
169*7f2fe78bSCy Schubert /* We cannot interpose this function as mech_type is an output parameter. */
gss_inquire_mech_for_saslname(OM_uint32 * minor_status,const gss_buffer_t sasl_mech_name,gss_OID * mech_type)170*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV gss_inquire_mech_for_saslname(
171*7f2fe78bSCy Schubert     OM_uint32           *minor_status,
172*7f2fe78bSCy Schubert     const gss_buffer_t   sasl_mech_name,
173*7f2fe78bSCy Schubert     gss_OID             *mech_type)
174*7f2fe78bSCy Schubert {
175*7f2fe78bSCy Schubert     OM_uint32       status, tmpMinor;
176*7f2fe78bSCy Schubert     gss_OID_set     mechSet = GSS_C_NO_OID_SET;
177*7f2fe78bSCy Schubert     size_t          i;
178*7f2fe78bSCy Schubert 
179*7f2fe78bSCy Schubert     if (minor_status != NULL)
180*7f2fe78bSCy Schubert         *minor_status = 0;
181*7f2fe78bSCy Schubert 
182*7f2fe78bSCy Schubert     if (mech_type != NULL)
183*7f2fe78bSCy Schubert         *mech_type = GSS_C_NO_OID;
184*7f2fe78bSCy Schubert 
185*7f2fe78bSCy Schubert     if (minor_status == NULL)
186*7f2fe78bSCy Schubert         return GSS_S_CALL_INACCESSIBLE_WRITE;
187*7f2fe78bSCy Schubert 
188*7f2fe78bSCy Schubert     status = gss_indicate_mechs(minor_status, &mechSet);
189*7f2fe78bSCy Schubert     if (status != GSS_S_COMPLETE)
190*7f2fe78bSCy Schubert         return status;
191*7f2fe78bSCy Schubert 
192*7f2fe78bSCy Schubert     for (i = 0, status = GSS_S_BAD_MECH; i < mechSet->count; i++) {
193*7f2fe78bSCy Schubert         gss_mechanism mech;
194*7f2fe78bSCy Schubert         char mappedName[OID_SASL_NAME_LENGTH + 1];
195*7f2fe78bSCy Schubert 
196*7f2fe78bSCy Schubert         mech = gssint_get_mechanism(&mechSet->elements[i]);
197*7f2fe78bSCy Schubert         if (mech != NULL && mech->gss_inquire_mech_for_saslname != NULL) {
198*7f2fe78bSCy Schubert             status = mech->gss_inquire_mech_for_saslname(minor_status,
199*7f2fe78bSCy Schubert                                                          sasl_mech_name,
200*7f2fe78bSCy Schubert                                                          mech_type);
201*7f2fe78bSCy Schubert             if (status == GSS_S_COMPLETE)
202*7f2fe78bSCy Schubert                 break;
203*7f2fe78bSCy Schubert         }
204*7f2fe78bSCy Schubert         if (status == GSS_S_BAD_MECH &&
205*7f2fe78bSCy Schubert             sasl_mech_name->length == OID_SASL_NAME_LENGTH &&
206*7f2fe78bSCy Schubert             oidToSaslName(&tmpMinor, &mechSet->elements[i],
207*7f2fe78bSCy Schubert                           mappedName) == GSS_S_COMPLETE &&
208*7f2fe78bSCy Schubert             memcmp(sasl_mech_name->value, mappedName,
209*7f2fe78bSCy Schubert                    OID_SASL_NAME_LENGTH) == 0) {
210*7f2fe78bSCy Schubert             if (mech_type != NULL)
211*7f2fe78bSCy Schubert                 *mech_type = &mech->mech_type;
212*7f2fe78bSCy Schubert             status = GSS_S_COMPLETE;
213*7f2fe78bSCy Schubert             break;
214*7f2fe78bSCy Schubert         }
215*7f2fe78bSCy Schubert     }
216*7f2fe78bSCy Schubert 
217*7f2fe78bSCy Schubert     gss_release_oid_set(&tmpMinor, &mechSet);
218*7f2fe78bSCy Schubert 
219*7f2fe78bSCy Schubert     return status;
220*7f2fe78bSCy Schubert }
221