Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : simple kerberos5/SPNEGO routines
4 : Copyright (C) Andrew Tridgell 2001
5 : Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
6 : Copyright (C) Luke Howard 2003
7 : Copyright (C) Jeremy Allison 2010
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "../libcli/auth/spnego.h"
25 : #include "smb_krb5.h"
26 : #include "../lib/util/asn1.h"
27 :
28 : /*
29 : parse a negTokenInit packet giving a GUID, a list of supported
30 : OIDs (the mechanisms) and a principal name string
31 : */
32 86 : bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
33 : DATA_BLOB blob,
34 : char *OIDs[ASN1_MAX_OIDS],
35 : char **principal,
36 : DATA_BLOB *secblob)
37 : {
38 : int i;
39 86 : bool ret = false;
40 : ASN1_DATA *data;
41 :
42 1806 : for (i = 0; i < ASN1_MAX_OIDS; i++) {
43 1720 : OIDs[i] = NULL;
44 : }
45 :
46 86 : if (principal) {
47 86 : *principal = NULL;
48 : }
49 86 : if (secblob) {
50 0 : *secblob = data_blob_null;
51 : }
52 :
53 86 : data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
54 86 : if (data == NULL) {
55 0 : return false;
56 : }
57 :
58 86 : if (!asn1_load(data, blob)) goto err;
59 :
60 86 : if (!asn1_start_tag(data,ASN1_APPLICATION(0))) goto err;
61 :
62 86 : if (!asn1_check_OID(data,OID_SPNEGO)) goto err;
63 :
64 : /* negTokenInit [0] NegTokenInit */
65 86 : if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
66 86 : if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
67 :
68 : /* mechTypes [0] MechTypeList OPTIONAL */
69 :
70 : /* Not really optional, we depend on this to decide
71 : * what mechanisms we have to work with. */
72 :
73 86 : if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err;
74 86 : if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err;
75 344 : for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) {
76 258 : if (!asn1_read_OID(data,ctx, &OIDs[i])) {
77 0 : goto err;
78 : }
79 258 : if (asn1_has_error(data)) {
80 0 : goto err;
81 : }
82 : }
83 86 : OIDs[i] = NULL;
84 86 : if (!asn1_end_tag(data)) goto err;
85 86 : if (!asn1_end_tag(data)) goto err;
86 :
87 : /*
88 : Win7 + Live Sign-in Assistant attaches a mechToken
89 : ASN1_CONTEXT(2) to the negTokenInit packet
90 : which breaks our negotiation if we just assume
91 : the next tag is ASN1_CONTEXT(3).
92 : */
93 :
94 86 : if (asn1_peek_tag(data, ASN1_CONTEXT(1))) {
95 : uint8_t flags;
96 :
97 : /* reqFlags [1] ContextFlags OPTIONAL */
98 0 : if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err;
99 0 : if (!asn1_start_tag(data, ASN1_BIT_STRING)) goto err;
100 0 : while (asn1_tag_remaining(data) > 0) {
101 0 : if (!asn1_read_uint8(data, &flags)) goto err;
102 : }
103 0 : if (!asn1_end_tag(data)) goto err;
104 0 : if (!asn1_end_tag(data)) goto err;
105 : }
106 :
107 86 : if (asn1_peek_tag(data, ASN1_CONTEXT(2))) {
108 0 : DATA_BLOB sblob = data_blob_null;
109 : /* mechToken [2] OCTET STRING OPTIONAL */
110 0 : if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err;
111 0 : if (!asn1_read_OctetString(data, ctx, &sblob)) goto err;
112 0 : if (!asn1_end_tag(data)) {
113 0 : data_blob_free(&sblob);
114 0 : goto err;
115 : }
116 0 : if (secblob) {
117 0 : *secblob = sblob;
118 : } else {
119 0 : data_blob_free(&sblob);
120 : }
121 : }
122 :
123 86 : if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
124 86 : char *princ = NULL;
125 : /* mechListMIC [3] OCTET STRING OPTIONAL */
126 86 : if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err;
127 86 : if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err;
128 86 : if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err;
129 86 : if (!asn1_read_GeneralString(data, ctx, &princ)) goto err;
130 86 : if (!asn1_end_tag(data)) goto err;
131 86 : if (!asn1_end_tag(data)) goto err;
132 86 : if (!asn1_end_tag(data)) goto err;
133 86 : if (principal) {
134 86 : *principal = princ;
135 : } else {
136 0 : TALLOC_FREE(princ);
137 : }
138 : }
139 :
140 86 : if (!asn1_end_tag(data)) goto err;
141 86 : if (!asn1_end_tag(data)) goto err;
142 :
143 86 : if (!asn1_end_tag(data)) goto err;
144 :
145 86 : ret = !asn1_has_error(data);
146 :
147 86 : err:
148 :
149 86 : if (asn1_has_error(data)) {
150 : int j;
151 0 : if (principal) {
152 0 : TALLOC_FREE(*principal);
153 : }
154 0 : if (secblob) {
155 0 : data_blob_free(secblob);
156 : }
157 0 : for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) {
158 0 : TALLOC_FREE(OIDs[j]);
159 : }
160 : }
161 :
162 86 : asn1_free(data);
163 86 : return ret;
164 : }
165 :
166 : /*
167 : generate a krb5 GSS-API wrapper packet given a ticket
168 : */
169 0 : DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const uint8_t tok_id[2])
170 : {
171 : ASN1_DATA *data;
172 0 : DATA_BLOB ret = data_blob_null;
173 :
174 0 : data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
175 0 : if (data == NULL) {
176 0 : return data_blob_null;
177 : }
178 :
179 0 : if (!asn1_push_tag(data, ASN1_APPLICATION(0))) goto err;
180 0 : if (!asn1_write_OID(data, OID_KERBEROS5)) goto err;
181 :
182 0 : if (!asn1_write(data, tok_id, 2)) goto err;
183 0 : if (!asn1_write(data, ticket.data, ticket.length)) goto err;
184 0 : if (!asn1_pop_tag(data)) goto err;
185 :
186 0 : if (!asn1_extract_blob(data, ctx, &ret)) {
187 0 : goto err;
188 : }
189 :
190 0 : asn1_free(data);
191 0 : data = NULL;
192 :
193 0 : err:
194 :
195 0 : if (data != NULL) {
196 0 : if (asn1_has_error(data)) {
197 0 : DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n",
198 : (int)asn1_current_ofs(data)));
199 : }
200 :
201 0 : asn1_free(data);
202 : }
203 :
204 0 : return ret;
205 : }
|