OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / pluto / packet.c
1 /* parsing packets: formats and tools
2  * Copyright (C) 1997 Angelos D. Keromytis.
3  * Copyright (C) 1998-2001  D. Hugh Redelmeier.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  *
15  * RCSID $Id: packet.c,v 1.29 2002/03/15 21:27:19 dhr Exp $
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stddef.h>
21 #include <netinet/in.h>
22 #include <string.h>
23
24 #include <freeswan.h>
25
26 #include "constants.h"
27 #include "defs.h"
28 #include "log.h"
29 #include "packet.h"
30 #include "whack.h"      /* for RC_LOG_SERIOUS */
31
32 /* ISAKMP Header: for all messages
33  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.1
34  *                      1                   2                   3
35  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
36  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37  * !                          Initiator                            !
38  * !                            Cookie                             !
39  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40  * !                          Responder                            !
41  * !                            Cookie                             !
42  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43  * !  Next Payload ! MjVer ! MnVer ! Exchange Type !     Flags     !
44  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45  * !                          Message ID                           !
46  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47  * !                            Length                             !
48  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49  */
50
51 static field_desc isa_fields[] = {
52     { ft_raw, COOKIE_SIZE, "initiator cookie", NULL },
53     { ft_raw, COOKIE_SIZE, "responder cookie", NULL },
54     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
55     { ft_enum, 8/BITS_PER_BYTE, "ISAKMP version", &version_names },
56     { ft_enum, 8/BITS_PER_BYTE, "exchange type", &exchange_names },
57     { ft_set, 8/BITS_PER_BYTE, "flags", flag_bit_names },
58     { ft_raw, 32/BITS_PER_BYTE, "message ID", NULL },
59     { ft_len, 32/BITS_PER_BYTE, "length", NULL },
60     { ft_end, 0, NULL, NULL }
61 };
62
63 struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isakmp_hdr) };
64
65 /* Generic portion of all ISAKMP payloads.
66  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.2
67  * This describes the first 32-bit chunk of all payloads.
68  * The previous next payload depends on the actual payload type.
69  *                      1                   2                   3
70  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
71  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72  * ! Next Payload  !   RESERVED    !         Payload Length        !
73  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74  */
75
76 static field_desc isag_fields[] = {
77     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
78     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
79     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
80     { ft_end, 0, NULL, NULL }
81 };
82
83 struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) };
84
85
86 /* ISAKMP Data Attribute (generic representation within payloads)
87  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.3
88  * This is not a payload type.
89  * In TLV format, this is followed by a value field.
90  *                      1                   2                   3
91  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
92  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93  * !A!       Attribute Type        !    AF=0  Attribute Length     !
94  * !F!                             !    AF=1  Attribute Value      !
95  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96  * .                   AF=0  Attribute Value                       .
97  * .                   AF=1  Not Transmitted                       .
98  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99  */
100
101 /* Oakley Attributes */
102 static field_desc isaat_fields_oakley[] = {
103     { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &oakley_attr_names },
104     { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
105     { ft_end, 0, NULL, NULL }
106 };
107
108 struct_desc isakmp_oakley_attribute_desc = {
109     "ISAKMP Oakley attribute",
110     isaat_fields_oakley, sizeof(struct isakmp_attribute) };
111
112 /* IPsec DOI Attributes */
113 static field_desc isaat_fields_ipsec[] = {
114     { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &ipsec_attr_names },
115     { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
116     { ft_end, 0, NULL, NULL }
117 };
118
119 struct_desc isakmp_ipsec_attribute_desc = {
120     "ISAKMP IPsec DOI attribute",
121     isaat_fields_ipsec, sizeof(struct isakmp_attribute) };
122
123 /* ISAKMP Security Association Payload
124  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.4
125  * A variable length Situation follows.
126  * Previous next payload: ISAKMP_NEXT_SA
127  *                      1                   2                   3
128  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
129  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130  * ! Next Payload  !   RESERVED    !         Payload Length        !
131  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132  * !              Domain of Interpretation  (DOI)                  !
133  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
134  * !                                                               !
135  * ~                           Situation                           ~
136  * !                                                               !
137  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138  */
139 static field_desc isasa_fields[] = {
140     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
141     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
142     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
143     { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
144     { ft_end, 0, NULL, NULL }
145 };
146
147 struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) };
148
149 static field_desc ipsec_sit_field[] = {
150     { ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names },
151     { ft_end, 0, NULL, NULL }
152 };
153
154 struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) };
155
156 /* ISAKMP Proposal Payload
157  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.5
158  * A variable length SPI follows.
159  * Previous next payload: ISAKMP_NEXT_P
160  *                      1                   2                   3
161  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
162  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163  * ! Next Payload  !   RESERVED    !         Payload Length        !
164  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165  * !  Proposal #   !  Protocol-Id  !    SPI Size   !# of Transforms!
166  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
167  * !                        SPI (variable)                         !
168  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
169  */
170 static field_desc isap_fields[] = {
171     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
172     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
173     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
174     { ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL },
175     { ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names },
176     { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
177     { ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL },
178     { ft_end, 0, NULL, NULL }
179 };
180
181 struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) };
182
183 /* ISAKMP Transform Payload
184  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.6
185  * Variable length SA Attributes follow.
186  * Previous next payload: ISAKMP_NEXT_T
187  *                      1                   2                   3
188  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
189  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190  * ! Next Payload  !   RESERVED    !         Payload Length        !
191  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192  * !  Transform #  !  Transform-Id !           RESERVED2           !
193  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
194  * !                                                               !
195  * ~                        SA Attributes                          ~
196  * !                                                               !
197  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
198  */
199
200 /* PROTO_ISAKMP */
201 static field_desc isat_fields_isakmp[] = {
202     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
203     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
204     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
205     { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
206     { ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names },
207     { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
208     { ft_end, 0, NULL, NULL }
209 };
210
211 struct_desc isakmp_isakmp_transform_desc = {
212     "ISAKMP Transform Payload (ISAKMP)",
213     isat_fields_isakmp, sizeof(struct isakmp_transform) };
214
215 /* PROTO_IPSEC_AH */
216 static field_desc isat_fields_ah[] = {
217     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
218     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
219     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
220     { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
221     { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transformid_names },
222     { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
223     { ft_end, 0, NULL, NULL }
224 };
225
226 struct_desc isakmp_ah_transform_desc = {
227     "ISAKMP Transform Payload (AH)",
228     isat_fields_ah, sizeof(struct isakmp_transform) };
229
230 /* PROTO_IPSEC_ESP */
231 static field_desc isat_fields_esp[] = {
232     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
233     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
234     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
235     { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
236     { ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transformid_names },
237     { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
238     { ft_end, 0, NULL, NULL }
239 };
240
241 struct_desc isakmp_esp_transform_desc = {
242     "ISAKMP Transform Payload (ESP)",
243     isat_fields_esp, sizeof(struct isakmp_transform) };
244
245 /* PROTO_IPCOMP */
246 static field_desc isat_fields_ipcomp[] = {
247     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
248     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
249     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
250     { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
251     { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names },
252     { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
253     { ft_end, 0, NULL, NULL }
254 };
255
256 struct_desc isakmp_ipcomp_transform_desc = {
257     "ISAKMP Transform Payload (COMP)",
258     isat_fields_ipcomp, sizeof(struct isakmp_transform) };
259
260
261 /* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones.
262  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.7
263  * Variable Key Exchange Data follow the generic fields.
264  * Previous next payload: ISAKMP_NEXT_KE
265  *                      1                   2                   3
266  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
267  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268  * ! Next Payload  !   RESERVED    !         Payload Length        !
269  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
270  * !                                                               !
271  * ~                       Key Exchange Data                       ~
272  * !                                                               !
273  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
274  */
275 struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) };
276
277 /* ISAKMP Identification Payload
278  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.8
279  * See "struct identity" declared later.
280  * Variable length Identification Data follow.
281  * Previous next payload: ISAKMP_NEXT_ID
282  *                      1                   2                   3
283  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
284  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
285  * ! Next Payload  !   RESERVED    !         Payload Length        !
286  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287  * !   ID Type     !             DOI Specific ID Data              !
288  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
289  * !                                                               !
290  * ~                   Identification Data                         ~
291  * !                                                               !
292  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
293  */
294 static field_desc isaid_fields[] = {
295     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
296     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
297     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
298     { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },      /* ??? depends on DOI? */
299     { ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL },        /* ??? depends on DOI? */
300     { ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL },       /* ??? depends on DOI? */
301     { ft_end, 0, NULL, NULL }
302 };
303
304 struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) };
305
306 /* IPSEC Identification Payload Content
307  * layout from draft-ietf-ipsec-ipsec-doi-08.txt section 4.6.2
308  * See struct isakmp_id declared earlier.
309  * Note: Hashing skips the ISAKMP generic payload header
310  * Variable length Identification Data follow.
311  *                      1                   2                   3
312  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
313  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314  * !  Next Payload !   RESERVED    !        Payload Length         !
315  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316  * !   ID Type     !  Protocol ID  !             Port              !
317  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318  * ~                     Identification Data                       ~
319  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
320  */
321 static field_desc isaiid_fields[] = {
322     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
323     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
324     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
325     { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
326     { ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL },   /* ??? UDP/TCP or 0? */
327     { ft_nat, 16/BITS_PER_BYTE, "port", NULL },
328     { ft_end, 0, NULL, NULL }
329 };
330
331 struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) };
332
333 /* ISAKMP Certificate Payload: no fixed fields beyond the generic ones.
334  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.9
335  * Variable length Certificate Data follow the generic fields.
336  * Previous next payload: ISAKMP_NEXT_CERT.
337  *                      1                   2                   3
338  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
339  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
340  * ! Next Payload  !   RESERVED    !         Payload Length        !
341  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
342  * ! Cert Encoding !                                               !
343  * +-+-+-+-+-+-+-+-+                                               !
344  * ~                       Certificate Data                        ~
345  * !                                                               !
346  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
347  */
348 static field_desc isacert_fields[] = {
349     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
350     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
351     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
352     { ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names },
353     { ft_end, 0, NULL, NULL }
354 };
355
356 struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE };
357
358 /* ISAKMP Certificate Request Payload: no fixed fields beyond the generic ones.
359  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.10
360  * Variable length Certificate Types and Certificate Authorities follow.
361  * Previous next payload: ISAKMP_NEXT_CR.
362  *                      1                   2                   3
363  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
364  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365  * ! Next Payload  !   RESERVED    !         Payload Length        !
366  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367  * !  Cert. Type   !                                               !
368  * +-+-+-+-+-+-+-+-+                                               !
369  * ~                    Certificate Authority                      ~
370  * !                                                               !
371  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372  */
373 static field_desc isacr_fields[] = {
374     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
375     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
376     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
377     { ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names },
378     { ft_end, 0, NULL, NULL }
379 };
380
381 struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE };
382
383 /* ISAKMP Hash Payload: no fixed fields beyond the generic ones.
384  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.11
385  * Variable length Hash Data follow.
386  * Previous next payload: ISAKMP_NEXT_HASH.
387  *                      1                   2                   3
388  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
389  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
390  * ! Next Payload  !   RESERVED    !         Payload Length        !
391  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
392  * !                                                               !
393  * ~                           Hash Data                           ~
394  * !                                                               !
395  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
396  */
397 struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) };
398
399 /* ISAKMP Signature Payload: no fixed fields beyond the generic ones.
400  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.12
401  * Variable length Signature Data follow.
402  * Previous next payload: ISAKMP_NEXT_SIG.
403  *                      1                   2                   3
404  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
405  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406  * ! Next Payload  !   RESERVED    !         Payload Length        !
407  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408  * !                                                               !
409  * ~                         Signature Data                        ~
410  * !                                                               !
411  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412  */
413 struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) };
414
415 /* ISAKMP Nonce Payload: no fixed fields beyond the generic ones.
416  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.13
417  * Variable length Nonce Data follow.
418  * Previous next payload: ISAKMP_NEXT_NONCE.
419  *                      1                   2                   3
420  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
421  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422  * ! Next Payload  !   RESERVED    !         Payload Length        !
423  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424  * !                                                               !
425  * ~                            Nonce Data                         ~
426  * !                                                               !
427  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
428  */
429 struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) };
430
431 /* ISAKMP Notification Payload
432  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.14
433  * This is followed by a variable length SPI
434  * and then possibly by variable length Notification Data.
435  * Previous next payload: ISAKMP_NEXT_N
436  *                      1                   2                   3
437  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
438  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
439  * ! Next Payload  !   RESERVED    !         Payload Length        !
440  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
441  * !              Domain of Interpretation  (DOI)                  !
442  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
443  * !  Protocol-ID  !   SPI Size    !      Notify Message Type      !
444  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
445  * !                                                               !
446  * ~                Security Parameter Index (SPI)                 ~
447  * !                                                               !
448  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
449  * !                                                               !
450  * ~                       Notification Data                       ~
451  * !                                                               !
452  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
453  */
454 static field_desc isan_fields[] = {
455     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
456     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
457     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
458     { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
459     { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL },   /* ??? really enum: ISAKMP, IPSEC, ESP, ... */
460     { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
461     { ft_nat, 16/BITS_PER_BYTE, "Notify Message Type", NULL },
462 #if 0
463     { ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", &ipsec_notification_names },
464 #endif
465     { ft_end, 0, NULL, NULL }
466 };
467
468 struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) };
469
470 /* ISAKMP Delete Payload
471  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.15
472  * This is followed by a variable length SPI.
473  * Previous next payload: ISAKMP_NEXT_D
474  *                      1                   2                   3
475  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
476  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
477  * ! Next Payload  !   RESERVED    !         Payload Length        !
478  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
479  * !              Domain of Interpretation  (DOI)                  !
480  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
481  * !  Protocol-Id  !   SPI Size    !           # of SPIs           !
482  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
483  * !                                                               !
484  * ~               Security Parameter Index(es) (SPI)              ~
485  * !                                                               !
486  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
487  */
488 static field_desc isad_fields[] = {
489     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
490     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
491     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
492     { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
493     { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL },   /* ??? really enum: ISAKMP, IPSEC */
494     { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
495     { ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL },
496     { ft_end, 0, NULL, NULL }
497 };
498
499 struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) };
500
501 /* ISAKMP Vendor ID Payload
502  * layout from draft-ietf-ipsec-isakmp-09.txt section 3.15
503  * This is followed by a variable length VID.
504  * Previous next payload: ISAKMP_NEXT_VID
505  *                      1                   2                   3
506  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
507  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
508  * ! Next Payload  !   RESERVED    !         Payload Length        !
509  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510  * !                                                               !
511  * ~                        Vendor ID (VID)                        ~
512  * !                                                               !
513  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514  */
515 struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) };
516
517 #ifdef NAT_TRAVERSAL
518 /* ISAKMP NAT-Traversal NAT-D
519  * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2
520  *
521  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
522  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523  * ! Next Payload  !   RESERVED    !         Payload Length        !
524  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525  * !                 HASH of the address and port                  !
526  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
527  */
528 struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) };
529
530 /* ISAKMP NAT-Traversal NAT-OA
531  * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2
532  *
533  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
534  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535  * ! Next Payload  !   RESERVED    !         Payload Length        !
536  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537  * !   ID Type     !   RESERVED    !            RESERVED           !
538  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539  * !         IPv4 (4 octets) or IPv6 address (16 octets)           !
540  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541  */
542 static field_desc isanat_oa_fields[] = {
543     { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
544     { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
545     { ft_len, 16/BITS_PER_BYTE, "length", NULL },
546     { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
547     { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL },
548     { ft_end, 0, NULL, NULL }
549 };
550
551 struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
552 #endif
553
554 /* descriptor for each payload type
555  *
556  * There is a slight problem in that some payloads differ, depending
557  * on the mode.  Since this is table only used for top-level payloads,
558  * Proposal and Transform payloads need not be handled.
559  * That leaves only Identification payloads as a problem.
560  * We make all these entries NULL
561  */
562 struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = {
563     NULL,                               /* 0 ISAKMP_NEXT_NONE (No other payload following) */
564     &isakmp_sa_desc,                    /* 1 ISAKMP_NEXT_SA (Security Association) */
565     NULL,                               /* 2 ISAKMP_NEXT_P (Proposal) */
566     NULL,                               /* 3 ISAKMP_NEXT_T (Transform) */
567     &isakmp_keyex_desc,                 /* 4 ISAKMP_NEXT_KE (Key Exchange) */
568     NULL,                               /* 5 ISAKMP_NEXT_ID (Identification) */
569     &isakmp_ipsec_certificate_desc,     /* 6 ISAKMP_NEXT_CERT (Certificate) */
570     &isakmp_ipsec_cert_req_desc,        /* 7 ISAKMP_NEXT_CR (Certificate Request) */
571     &isakmp_hash_desc,                  /* 8 ISAKMP_NEXT_HASH (Hash) */
572     &isakmp_signature_desc,             /* 9 ISAKMP_NEXT_SIG (Signature) */
573     &isakmp_nonce_desc,                 /* 10 ISAKMP_NEXT_NONCE (Nonce) */
574     &isakmp_notification_desc,          /* 11 ISAKMP_NEXT_N (Notification) */
575     &isakmp_delete_desc,                /* 12 ISAKMP_NEXT_D (Delete) */
576     &isakmp_vendor_id_desc,             /* 13 ISAKMP_NEXT_VID (Vendor ID) */
577 #ifdef NAT_TRAVERSAL
578         NULL,
579         &isakmp_nat_d,              /* 15=130 ISAKMP_NEXT_NATD (NAT-D) */
580         &isakmp_nat_oa,             /* 16=131 ISAKMP_NEXT_NATOA (NAT-OA) */
581 #endif
582 };
583
584 void
585 init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name)
586 {
587     pbs->container = NULL;
588     pbs->desc = NULL;
589     pbs->name = name;
590     pbs->start = pbs->cur = start;
591     pbs->roof = start + len;
592     pbs->lenfld = NULL;
593     pbs->lenfld_desc = NULL;
594 }
595
596 #ifdef DEBUG
597
598 /* print a host struct
599  *
600  * This code assumes that the network and host structure
601  * members have the same alignment and size!  This requires
602  * that all padding be explicit.
603  */
604 void
605 DBG_print_struct(const char *label, const void *struct_ptr
606 , struct_desc *sd, bool len_meaningful)
607 {
608     bool immediate = FALSE;
609     const u_int8_t *inp = struct_ptr;
610     field_desc *fp;
611
612     DBG_log("%s%s:", label, sd->name);
613
614     for (fp = sd->fields; fp->field_type != ft_end; fp++) {
615         int i = fp->size;
616         u_int32_t n = 0;
617
618         switch (fp->field_type) {
619         case ft_mbz:    /* must be zero */
620             inp += i;
621             break;
622         case ft_nat:    /* natural number (may be 0) */
623         case ft_len:    /* length of this struct and any following crud */
624         case ft_lv:     /* length/value field of attribute */
625         case ft_enum:   /* value from an enumeration */
626         case ft_loose_enum:     /* value from an enumeration with only some names known */
627         case ft_af_enum:        /* Attribute Format + value from an enumeration */
628         case ft_set:    /* bits representing set */
629             switch (i) {
630             case 8/BITS_PER_BYTE:
631                 n = *(const u_int8_t *)inp;
632                 break;
633             case 16/BITS_PER_BYTE:
634                 n = *(const u_int16_t *)inp;
635                 break;
636             case 32/BITS_PER_BYTE:
637                 n = *(const u_int32_t *)inp;
638                 break;
639             default:
640                 impossible();
641             }
642             switch (fp->field_type) {
643             case ft_len:        /* length of this struct and any following crud */
644             case ft_lv:         /* length/value field of attribute */
645                 if (!immediate && !len_meaningful)
646                     break;
647                 /* FALL THROUGH */
648             case ft_nat:        /* natural number (may be 0) */
649                 DBG_log("   %s: %lu", fp->name, (unsigned long)n);
650                 break;
651             case ft_af_enum:    /* Attribute Format + value from an enumeration */
652                 if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
653                     immediate = TRUE;
654                 /* FALL THROUGH */
655             case ft_enum:       /* value from an enumeration */
656             case ft_loose_enum: /* value from an enumeration with only some names known */
657                 DBG_log("   %s: %s", fp->name, enum_show(fp->desc, n));
658                 break;
659             case ft_set:        /* bits representing set */
660                 DBG_log("   %s: %s", fp->name, bitnamesof(fp->desc, n));
661                 break;
662             default:
663                 impossible();
664                 break;
665             }
666             inp += i;
667             break;
668
669         case ft_raw:    /* bytes to be left in network-order */
670             {
671                 char m[50];     /* arbitrary limit on name width in log */
672
673                 snprintf(m, sizeof(m), "   %s:", fp->name);
674                 DBG_dump(m, inp, i);
675                 inp += i;
676             }
677             break;
678         default:
679             impossible();
680             break;
681         }
682     }
683 }
684
685 static void
686 DBG_prefix_print_struct(const pb_stream *pbs
687 , const char *label, const void *struct_ptr
688 , struct_desc *sd, bool len_meaningful)
689 {
690     /* print out a title, with a prefix of asterisks to show
691      * the nesting level.
692      */
693     char space[40];     /* arbitrary limit on label+flock-of-* */
694     size_t len = strlen(label);
695
696     if (sizeof(space) <= len)
697     {
698         DBG_print_struct(label, struct_ptr, sd, len_meaningful);
699     }
700     else
701     {
702         const pb_stream *p = pbs;
703         char *pre = &space[sizeof(space) - (len + 1)];
704
705         strcpy(pre, label);
706
707         /* put at least one * out */
708         for (;;)
709         {
710             if (pre <= space)
711                 break;
712             *--pre = '*';
713             if (p == NULL)
714                 break;
715             p = p->container;
716         }
717         DBG_print_struct(pre, struct_ptr, sd, len_meaningful);
718     }
719 }
720
721 #endif
722
723 /* "parse" a network struct into a host struct.
724  *
725  * This code assumes that the network and host structure
726  * members have the same alignment and size!  This requires
727  * that all padding be explicit.
728  *
729  * If obj_pbs is supplied, a new pb_stream is created for the
730  * variable part of the structure (this depends on their
731  * being one length field in the structure).  The cursor of this
732  * new PBS is set to after the parsed part of the struct.
733  *
734  * This routine returns TRUE iff it succeeds.
735  */
736
737 bool
738 in_struct(void *struct_ptr, struct_desc *sd
739 , pb_stream *ins, pb_stream *obj_pbs)
740 {
741     err_t ugh = NULL;
742     u_int8_t *cur = ins->cur;
743
744     if (ins->roof - cur < (ptrdiff_t)sd->size) {
745         ugh = builddiag("not enough room in input packet for %s", sd->name);
746     } else {
747         u_int8_t *roof = cur + sd->size;    /* may be changed by a length field */
748         u_int8_t *outp = struct_ptr;
749         bool immediate = FALSE;
750         field_desc *fp;
751
752         for (fp = sd->fields; ugh == NULL; fp++) {
753             size_t i = fp->size;
754
755             passert(ins->roof - cur >= (ptrdiff_t)i);
756             passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i));
757             passert(outp - (cur - ins->cur) == struct_ptr);
758
759 #if 0
760             DBG(DBG_PARSING, DBG_log("%d %s"
761                 , (int) (cur - ins->cur), fp->name == NULL? "" : fp->name));
762 #endif
763             switch (fp->field_type) {
764             case ft_mbz:        /* must be zero */
765                 for (; i != 0; i--) {
766                     if (*cur++ != 0) {
767                         ugh = builddiag("byte %d of %s must be zero, but is not"
768                             , (int) (cur - ins->cur), sd->name);
769                         break;
770                     }
771                     *outp++ = '\0';     /* probably redundant */
772                 }
773                 break;
774
775             case ft_nat:        /* natural number (may be 0) */
776             case ft_len:        /* length of this struct and any following crud */
777             case ft_lv:         /* length/value field of attribute */
778             case ft_enum:       /* value from an enumeration */
779             case ft_loose_enum: /* value from an enumeration with only some names known */
780             case ft_af_enum:    /* Attribute Format + value from an enumeration */
781             case ft_set:        /* bits representing set */
782             {
783                 u_int32_t n = 0;
784
785                 for (; i != 0; i--)
786                     n = (n << BITS_PER_BYTE) | *cur++;
787
788                 switch (fp->field_type) {
789                 case ft_len:    /* length of this struct and any following crud */
790                 case ft_lv:     /* length/value field of attribute */
791                 {
792                     u_int32_t len = fp->field_type == ft_len? n
793                         : immediate? sd->size : n + sd->size;
794
795                     if (len < sd->size) {
796                         ugh = builddiag("%s of %s is smaller than minimum"
797                             , fp->name, sd->name);
798                     } else if (pbs_left(ins) < len) {
799                         ugh = builddiag("%s of %s is larger than can fit"
800                             , fp->name, sd->name);
801                     } else {
802                         roof = ins->cur + len;
803                     }
804                     break;
805                 }
806                 case ft_af_enum:        /* Attribute Format + value from an enumeration */
807                     if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
808                         immediate = TRUE;
809                     /* FALL THROUGH */
810                 case ft_enum:   /* value from an enumeration */
811                     if (enum_name(fp->desc, n) == NULL) {
812                         ugh = builddiag("%s of %s has an unknown value: %lu"
813                             , fp->name, sd->name, (unsigned long)n);
814                     }
815                     /* FALL THROUGH */
816                 case ft_loose_enum:     /* value from an enumeration with only some names known */
817                     break;
818                 case ft_set:    /* bits representing set */
819                     if (!testset(fp->desc, n)) {
820                         ugh = builddiag("bitset %s of %s has unknown member(s): %s"
821                             , fp->name, sd->name, bitnamesof(fp->desc, n));
822                     }
823                     break;
824                 default:
825                         break;
826                 }
827                 i = fp->size;
828                 switch (i) {
829                 case 8/BITS_PER_BYTE:
830                     *(u_int8_t *)outp = n;
831                     break;
832                 case 16/BITS_PER_BYTE:
833                     *(u_int16_t *)outp = n;
834                     break;
835                 case 32/BITS_PER_BYTE:
836                     *(u_int32_t *)outp = n;
837                     break;
838                 default:
839                     impossible();
840                 }
841                 outp += i;
842                 break;
843             }
844
845             case ft_raw:        /* bytes to be left in network-order */
846                 for (; i != 0; i--) {
847                     *outp++ = *cur++;
848                 }
849                 break;
850
851             case ft_end:        /* end of field list */
852                 passert(cur == ins->cur + sd->size);
853                 if (obj_pbs != NULL) {
854                     init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name);
855                     obj_pbs->container = ins;
856                     obj_pbs->desc = sd;
857                     obj_pbs->cur = cur;
858                 }
859                 ins->cur = roof;
860                 DBG(DBG_PARSING
861                     , DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE));
862                 return TRUE;
863
864             default:
865                 impossible();
866             }
867         }
868     }
869
870     /* some failure got us here: report it */
871     loglog(RC_LOG_SERIOUS, ugh);
872     return FALSE;
873 }
874
875 bool
876 in_raw(void *bytes, size_t len, pb_stream *ins, const char *name)
877 {
878     if (pbs_left(ins) < len)
879     {
880         loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name);
881         return FALSE;
882     }
883     else
884     {
885         if (bytes == NULL)
886         {
887             DBG(DBG_PARSING
888                 , DBG_log("skipping %u raw bytes of %s (%s)"
889                     , (unsigned) len, ins->name, name);
890                   DBG_dump(name, ins->cur, len));
891         }
892         else
893         {
894             memcpy(bytes, ins->cur, len);
895             DBG(DBG_PARSING
896                 , DBG_log("parsing %u raw bytes of %s into %s"
897                     , (unsigned) len, ins->name, name);
898                   DBG_dump(name, bytes, len));
899         }
900         ins->cur += len;
901         return TRUE;
902     }
903 }
904
905 /* "emit" a host struct into a network packet.
906  *
907  * This code assumes that the network and host structure
908  * members have the same alignment and size!  This requires
909  * that all padding be explicit.
910  *
911  * If obj_pbs is non-NULL, its pbs describes a new output stream set up
912  * to contain the object.  The cursor will be left at the variable part.
913  * This new stream must subsequently be finalized by close_output_pbs().
914  *
915  * The value of any field of type ft_len is computed, not taken
916  * from the input struct.  The length is actually filled in when
917  * the object's output stream is finalized.  If obj_pbs is NULL,
918  * finalization is done by out_struct before it returns.
919  *
920  * This routine returns TRUE iff it succeeds.
921  */
922
923 bool
924 out_struct(const void *struct_ptr, struct_desc *sd
925 , pb_stream *outs, pb_stream *obj_pbs)
926 {
927     err_t ugh = NULL;
928     const u_int8_t *inp = struct_ptr;
929     u_int8_t *cur = outs->cur;
930
931     DBG(DBG_EMITTING
932         , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL));
933
934     if (outs->roof - cur < (ptrdiff_t)sd->size) {
935         ugh = builddiag("not enough room left in output packet to place %s"
936             , sd->name);
937     } else {
938         bool immediate = FALSE;
939         pb_stream obj;
940         field_desc *fp;
941
942         obj.lenfld = NULL;  /* until a length field is discovered */
943         obj.lenfld_desc = NULL;
944
945         for (fp = sd->fields; ugh == NULL; fp++) {
946             size_t i = fp->size;
947
948             passert(outs->roof - cur >= (ptrdiff_t)i);
949             passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i));
950             passert(inp - (cur - outs->cur) == struct_ptr);
951
952 #if 0
953             DBG(DBG_EMITTING, DBG_log("%d %s"
954                 , (int) (cur - outs->cur), fp->name == NULL? "" : fp->name);
955 #endif
956             switch (fp->field_type) {
957             case ft_mbz:        /* must be zero */
958                 inp += i;
959                 for (; i != 0; i--)
960                     *cur++ = '\0';
961                 break;
962             case ft_nat:        /* natural number (may be 0) */
963             case ft_len:        /* length of this struct and any following crud */
964             case ft_lv:         /* length/value field of attribute */
965             case ft_enum:       /* value from an enumeration */
966             case ft_loose_enum: /* value from an enumeration with only some names known */
967             case ft_af_enum:    /* Attribute Format + value from an enumeration */
968             case ft_set:        /* bits representing set */
969             {
970                 u_int32_t n = 0;
971
972                 switch (i) {
973                 case 8/BITS_PER_BYTE:
974                     n = *(const u_int8_t *)inp;
975                     break;
976                 case 16/BITS_PER_BYTE:
977                     n = *(const u_int16_t *)inp;
978                     break;
979                 case 32/BITS_PER_BYTE:
980                     n = *(const u_int32_t *)inp;
981                     break;
982                 default:
983                     impossible();
984                 }
985
986                 switch (fp->field_type) {
987                 case ft_len:    /* length of this struct and any following crud */
988                 case ft_lv:     /* length/value field of attribute */
989                     if (immediate)
990                         break;  /* not a length */
991                     /* We can't check the length because it will likely
992                      * be filled in after variable part is supplied.
993                      * We do record where this is so that it can be
994                      * filled in by a subsequent close_output_pbs().
995                      */
996                     passert(obj.lenfld == NULL);        /* only one ft_len allowed */
997                     obj.lenfld = cur;
998                     obj.lenfld_desc = fp;
999                     break;
1000                 case ft_af_enum:        /* Attribute Format + value from an enumeration */
1001                     if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
1002                         immediate = TRUE;
1003                     /* FALL THROUGH */
1004                 case ft_enum:   /* value from an enumeration */
1005                     if (enum_name(fp->desc, n) == NULL) {
1006                         ugh = builddiag("%s of %s has an unknown value: %lu"
1007                             , fp->name, sd->name, (unsigned long)n);
1008                     }
1009                     /* FALL THROUGH */
1010                 case ft_loose_enum:     /* value from an enumeration with only some names known */
1011                     break;
1012                 case ft_set:    /* bits representing set */
1013                     if (!testset(fp->desc, n)) {
1014                         ugh = builddiag("bitset %s of %s has unknown member(s): %s"
1015                             , fp->name, sd->name, bitnamesof(fp->desc, n));
1016                     }
1017                     break;
1018                 default:
1019                     break;
1020                 }
1021
1022                 while (i-- != 0) {
1023                     cur[i] = (u_int8_t)n;
1024                     n >>= BITS_PER_BYTE;
1025                 }
1026                 inp += fp->size;
1027                 cur += fp->size;
1028                 break;
1029             }
1030             case ft_raw:        /* bytes to be left in network-order */
1031                 for (; i != 0; i--) {
1032                     *cur++ = *inp++;
1033                 }
1034                 break;
1035             case ft_end:        /* end of field list */
1036                 passert(cur == outs->cur + sd->size);
1037
1038                 obj.container = outs;
1039                 obj.desc = sd;
1040                 obj.name = sd->name;
1041                 obj.start = outs->cur;
1042                 obj.cur = cur;
1043                 obj.roof = outs->roof;  /* limit of possible */
1044                 /* obj.lenfld and obj.lenfld_desc already set */
1045
1046                 if (obj_pbs == NULL) {
1047                     close_output_pbs(&obj); /* fill in length field, if any */
1048                 } else {
1049                     /* We set outs->cur to outs->roof so that
1050                      * any attempt to output something into outs
1051                      * before obj is closed will trigger an error.
1052                      */
1053                     outs->cur = outs->roof;
1054
1055                     *obj_pbs = obj;
1056                 }
1057                 return TRUE;
1058
1059             default:
1060                 impossible();
1061                 break;
1062             }
1063         }
1064     }
1065
1066     /* some failure got us here: report it */
1067     loglog(RC_LOG_SERIOUS, ugh);        /* ??? serious, but errno not relevant */
1068     return FALSE;
1069 }
1070
1071 bool
1072 out_generic(u_int8_t np, struct_desc *sd
1073 , pb_stream *outs, pb_stream *obj_pbs)
1074 {
1075     struct isakmp_generic gen;
1076
1077     passert(sd->fields == isakmp_generic_desc.fields);
1078     gen.isag_np = np;
1079     return out_struct(&gen, sd, outs, obj_pbs);
1080 }
1081
1082 bool
1083 out_generic_raw(u_int8_t np, struct_desc *sd
1084 , pb_stream *outs, const void *bytes, size_t len, const char *name)
1085 {
1086     pb_stream pbs;
1087
1088     if (!out_generic(np, sd, outs, &pbs)
1089     || !out_raw(bytes, len, &pbs, name))
1090         return FALSE;
1091     close_output_pbs(&pbs);
1092     return TRUE;
1093 }
1094
1095 #if 1
1096 bool
1097 out_modify_previous_np(u_int8_t np, pb_stream *outs)
1098 {
1099         size_t len = (outs->cur - outs->start), offset;
1100         if (len < sizeof(struct isakmp_hdr)) {
1101                 return FALSE;
1102         }
1103         else if (len == sizeof(struct isakmp_hdr)) {
1104                 struct isakmp_hdr *hdr = (struct isakmp_hdr *)outs->start;
1105                 hdr->isa_np = np;
1106                 return TRUE;
1107         }
1108         else {
1109                 struct isakmp_generic *hdr;
1110                 for (offset = sizeof(struct isakmp_hdr); offset < len ;
1111                         offset += ntohs(hdr->isag_length)) {
1112                         if ((len - offset) < sizeof(struct isakmp_generic))
1113                                 return FALSE;
1114                         hdr = (struct isakmp_generic *)(outs->start+offset);
1115                         if ((len - offset) < ntohs(hdr->isag_length))
1116                                 return FALSE;
1117                         if ((len - offset) == ntohs(hdr->isag_length)) {
1118                                 hdr->isag_np = np;
1119                                 return TRUE;
1120                         }
1121                 }
1122         }
1123         return FALSE;
1124 }
1125 #endif
1126
1127 bool
1128 out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name)
1129 {
1130     if (pbs_left(outs) < len)
1131     {
1132         loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s"
1133             , (unsigned long) len, name, outs->name);
1134         return FALSE;
1135     }
1136     else
1137     {
1138         DBG(DBG_EMITTING
1139             , DBG_log("emitting %u raw bytes of %s into %s"
1140                 , (unsigned) len, name, outs->name);
1141               DBG_dump(name, bytes, len));
1142         memcpy(outs->cur, bytes, len);
1143         outs->cur += len;
1144         return TRUE;
1145     }
1146 }
1147
1148 bool
1149 out_zero(size_t len, pb_stream *outs, const char *name)
1150 {
1151     if (pbs_left(outs) < len)
1152     {
1153         loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name);
1154         return FALSE;
1155     }
1156     else
1157     {
1158         DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s"
1159             , (unsigned) len, name, outs->name));
1160         memset(outs->cur, 0x00, len);
1161         outs->cur += len;
1162         return TRUE;
1163     }
1164 }
1165
1166 /* Record current length.
1167  * Note: currently, this may be repeated any number of times;
1168  * the last one wins.
1169  */
1170 void
1171 close_output_pbs(pb_stream *pbs)
1172 {
1173     if (pbs->lenfld != NULL)
1174     {
1175         u_int32_t len = pbs_offset(pbs);
1176         int i = pbs->lenfld_desc->size;
1177
1178         if (pbs->lenfld_desc->field_type == ft_lv)
1179             len -= sizeof(struct isakmp_attribute);
1180         DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu"
1181             , pbs->name, (unsigned long) len));
1182         while (i-- != 0) {
1183             pbs->lenfld[i] = (u_int8_t)len;
1184             len >>= BITS_PER_BYTE;
1185         }
1186     }
1187     if (pbs->container != NULL)
1188         pbs->container->cur = pbs->cur; /* pass space utilization up */
1189 }