handle multi-part files
[tridge/junkcode.git] / asn1.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    simple SPNEGO routines
5    Copyright (C) Andrew Tridgell 2001
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <sys/types.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <ctype.h>
27
28 #define BOOL int
29 #define True 1
30 #define False 0
31 #define Realloc realloc
32
33 struct nesting {
34         off_t start;
35         char *name;
36         struct nesting *next;
37 };
38
39 typedef struct {
40         uint8 *data;
41         size_t length;
42         off_t ofs;
43         struct nesting *nesting;
44 } ASN1_DATA;
45
46 static BOOL asn1_write(ASN1_DATA data, void *p, int len)
47 {
48         if (data.length < data.ofs+len) {
49                 data.data = Realloc(data.data, data.ofs+len);
50                 if (!data.data) return False;
51                 data.length = data.ofs+len;
52         }
53         memcpy(data.data + data.ofs, p, len);
54         data.ofs += len;
55 }
56
57 static BOOL asn1_push_tag(ASN1_DATA data, const char *tagstr, uint8 tag)
58 {
59         struct nesting *nesting;
60         uint8 fill;
61
62         asn1_write(data, tag);
63         nesting = (struct nesting *)malloc(sizeof(struct nesting));
64         if (!nesting) return False;
65
66         nesting->start = data.ofs;
67         nesting->name = strdup(tagstr);
68         nesting->next = data.nesting;
69         data.nesting = nesting;
70         fill = 0xff;
71         asn1_write(data, &fill, 1);
72         return True;
73 }
74
75 static BOOL asn1_pop_tag(ASN1_DATA data, const char *tagstr)
76 {
77         struct nesting *nesting;
78
79         nesting = data.nesting;
80
81         if (!nesting || strcmp(tagstr, nesting->name) != 0) {
82                 return False;
83         }
84         data.data[nesting->start] = data.ofs - nesting->start;
85         data.nesting = nesting->next;
86         free(nesting->name);
87         free(nesting);
88         return True;
89 }
90
91
92 static BOOL asn1_write_uint8(ASN1_DATA data, uint8 v)
93 {
94         return asn1_write(data, &v, 1);
95 }
96
97
98 static BOOL asn1_write_OID(ASN1_DATA data, const char *OID)
99 {
100         long v, v2;
101         char *p = (char *)OID;
102
103         asn1_push_tag(data, "OID", 0x6);
104         v = strtol(p, &p, 10);
105         v2 = strtol(p, &p, 10);
106         asn1_write_uint8(data, 40*v + v2);
107         while (*p) {
108                 v = strtol(p, &p, 10);
109                 if (v >= (1<<29)) asn1_write_uint8(data, 0x80 | ((v>>29)&0xff));
110                 if (v >= (1<<22)) asn1_write_uint8(data, 0x80 | ((v>>22)&0xff));
111                 if (v >= (1<<15)) asn1_write_uint8(data, 0x80 | ((v>>15)&0xff));
112                 if (v >= (1<<8)) asn1_write_uint8(data, 0x80 | ((v>>8)&0xff));
113                 asn1_write_uint8(data, 0x80 | ((v>>15)&0xff));
114         }
115         asn1_pop_tag(data, "OID");
116         return True;
117 }
118
119 static BOOL asn1_write_GeneralString(ASN1_DATA data, const char *s)
120 {
121         asn1_push_tag(data, "GS", 0x1b);
122         asn1_write(data, s, strlen(s));
123         asn1_pop_tag(data, "GS");
124 }
125
126 /*
127   generate a negTokenInit packet given a GUID, a list of supported
128   OIDs (the mechanisms) and a principle name string 
129 */
130 PACKET_DATA spnego_gen_negTokenInit(uint8 guid[16], 
131                                     const char **OIDs, 
132                                     const char *principle)
133 {
134         int i;
135
136         ASN1_DATA data;
137
138         ZERO_STRUCT(data);
139
140         asn1_write(data, guid, 16);
141         asn1_push_tag(data,"SPNEGO", 0x60);
142         asn1_write_OID(data,"1 3 6 1 5 5 2");
143         asn1_push_tag(data,"MECHS", 0xa0);
144         asn1_push_tag(data,"SEQ1", 0x30);
145
146         asn1_push_tag(data,"[0]", 0xa0);
147         asn1_push_tag(data,"SEQ1.1", 0x30);
148         for (i=0; OIDs[i]; i++) {
149                 asn1_write_OID(data,OIDs[i]);
150         }
151         asn1_pop_tag(data,"SEQ1.1");
152         asn1_pop_tag(data,"[0]");
153
154         asn1_push_tag(data,"[3]", 0xa3);
155         asn1_push_tag(data,"SEQ1.2", 0x30);
156         asn1_push_tag(data,"[0]", 0xa0);
157         asn1_write_GeneralString(data,principle);
158         asn1_pop_tag(data,"[0]");
159         asn1_pop_tag(data,"SEQ1.2");
160         asn1_pop_tag(data,"[3]");
161
162         asn1_pop_tag(data,"SEQ1");
163         asn1_pop_tag(data,"MECHS");
164
165         asn1_check_empty(data);
166 }
167
168
169 #if 1
170 main()
171 {
172         PACKET_DATA data;
173         uint8 guid[16] = "012345678901234";
174
175         data = spnego_gen_negTokenInit(guid, 
176                 {"1 2 840 48018 1 2 2", "1 2 840 113554 1 2 2"},
177                                        "blu$@VNET2.HOME.SAMBA.ORG");
178 }
179
180 #endif