aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-14 16:39:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-14 16:39:34 -0400
commitd25282d1c9b9bc4cda7f9d3c0205108e99aa7a9d (patch)
treef414482d768b015a609924293b779b4ad0b8f764 /scripts
parentb6eea87fc6850d3531a64a27d2323a4498cd4e43 (diff)
parentdbadc17683e6c673a69b236c0f041b931cc55c42 (diff)
Merge branch 'modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module signing support from Rusty Russell: "module signing is the highlight, but it's an all-over David Howells frenzy..." Hmm "Magrathea: Glacier signing key". Somebody has been reading too much HHGTTG. * 'modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (37 commits) X.509: Fix indefinite length element skip error handling X.509: Convert some printk calls to pr_devel asymmetric keys: fix printk format warning MODSIGN: Fix 32-bit overflow in X.509 certificate validity date checking MODSIGN: Make mrproper should remove generated files. MODSIGN: Use utf8 strings in signer's name in autogenerated X.509 certs MODSIGN: Use the same digest for the autogen key sig as for the module sig MODSIGN: Sign modules during the build process MODSIGN: Provide a script for generating a key ID from an X.509 cert MODSIGN: Implement module signature checking MODSIGN: Provide module signing public keys to the kernel MODSIGN: Automatically generate module signing keys if missing MODSIGN: Provide Kconfig options MODSIGN: Provide gitignore and make clean rules for extra files MODSIGN: Add FIPS policy module: signature checking hook X.509: Add a crypto key parser for binary (DER) X.509 certificates MPILIB: Provide a function to read raw data into an MPI X.509: Add an ASN.1 decoder X.509: Add simple ASN.1 grammar compiler ...
Diffstat (limited to 'scripts')
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Makefile2
-rw-r--r--scripts/Makefile.build11
-rw-r--r--scripts/Makefile.modpost77
-rw-r--r--scripts/asn1_compiler.c1545
-rw-r--r--scripts/sign-file115
-rwxr-xr-xscripts/x509keyid268
7 files changed, 2018 insertions, 1 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 65f362d931b5..fb070fa1038f 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -10,3 +10,4 @@ ihex2fw
10recordmcount 10recordmcount
11docproc 11docproc
12sortextable 12sortextable
13asn1_compiler
diff --git a/scripts/Makefile b/scripts/Makefile
index a55b0067758a..01e7adb838d9 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -16,8 +16,10 @@ hostprogs-$(CONFIG_VT) += conmakehash
16hostprogs-$(CONFIG_IKCONFIG) += bin2c 16hostprogs-$(CONFIG_IKCONFIG) += bin2c
17hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount 17hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
18hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable 18hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
19hostprogs-$(CONFIG_ASN1) += asn1_compiler
19 20
20HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include 21HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
22HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
21 23
22always := $(hostprogs-y) $(hostprogs-m) 24always := $(hostprogs-y) $(hostprogs-m)
23 25
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index ff1720d28d0c..0e801c3cdaf8 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -354,6 +354,17 @@ quiet_cmd_cpp_lds_S = LDS $@
354$(obj)/%.lds: $(src)/%.lds.S FORCE 354$(obj)/%.lds: $(src)/%.lds.S FORCE
355 $(call if_changed_dep,cpp_lds_S) 355 $(call if_changed_dep,cpp_lds_S)
356 356
357# ASN.1 grammar
358# ---------------------------------------------------------------------------
359quiet_cmd_asn1_compiler = ASN.1 $@
360 cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
361 $(subst .h,.c,$@) $(subst .c,.h,$@)
362
363.PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h
364
365$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
366 $(call cmd,asn1_compiler)
367
357# Build the compiled-in targets 368# Build the compiled-in targets
358# --------------------------------------------------------------------------- 369# ---------------------------------------------------------------------------
359 370
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index a1cb0222ebe6..002089141df4 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -14,7 +14,8 @@
14# 3) create one <module>.mod.c file pr. module 14# 3) create one <module>.mod.c file pr. module
15# 4) create one Module.symvers file with CRC for all exported symbols 15# 4) create one Module.symvers file with CRC for all exported symbols
16# 5) compile all <module>.mod.c files 16# 5) compile all <module>.mod.c files
17# 6) final link of the module to a <module.ko> file 17# 6) final link of the module to a <module.ko> (or <module.unsigned>) file
18# 7) signs the modules to a <module.ko> file
18 19
19# Step 3 is used to place certain information in the module's ELF 20# Step 3 is used to place certain information in the module's ELF
20# section, including information such as: 21# section, including information such as:
@@ -32,6 +33,8 @@
32# Step 4 is solely used to allow module versioning in external modules, 33# Step 4 is solely used to allow module versioning in external modules,
33# where the CRC of each module is retrieved from the Module.symvers file. 34# where the CRC of each module is retrieved from the Module.symvers file.
34 35
36# Step 7 is dependent on CONFIG_MODULE_SIG being enabled.
37
35# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined 38# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
36# symbols in the final module linking stage 39# symbols in the final module linking stage
37# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. 40# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
116targets += $(modules:.ko=.mod.o) 119targets += $(modules:.ko=.mod.o)
117 120
118# Step 6), final link of the modules 121# Step 6), final link of the modules
122ifneq ($(CONFIG_MODULE_SIG),y)
119quiet_cmd_ld_ko_o = LD [M] $@ 123quiet_cmd_ld_ko_o = LD [M] $@
120 cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ 124 cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
121 $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ 125 $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
@@ -125,7 +129,78 @@ $(modules): %.ko :%.o %.mod.o FORCE
125 $(call if_changed,ld_ko_o) 129 $(call if_changed,ld_ko_o)
126 130
127targets += $(modules) 131targets += $(modules)
132else
133quiet_cmd_ld_ko_unsigned_o = LD [M] $@
134 cmd_ld_ko_unsigned_o = \
135 $(LD) -r $(LDFLAGS) \
136 $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
137 -o $@ $(filter-out FORCE,$^) \
138 $(if $(AFTER_LINK),; $(AFTER_LINK))
139
140$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE
141 $(call if_changed,ld_ko_unsigned_o)
142
143targets += $(modules:.ko=.ko.unsigned)
144
145# Step 7), sign the modules
146MODSECKEY = ./signing_key.priv
147MODPUBKEY = ./signing_key.x509
148
149ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY))
150ifeq ($(KBUILD_SRC),)
151 # no O= is being used
152 SCRIPTS_DIR := scripts
153else
154 SCRIPTS_DIR := $(KBUILD_SRC)/scripts
155endif
156SIGN_MODULES := 1
157else
158SIGN_MODULES := 0
159endif
160
161# only sign if it's an in-tree module
162ifneq ($(KBUILD_EXTMOD),)
163SIGN_MODULES := 0
164endif
128 165
166# We strip the module as best we can - note that using both strip and eu-strip
167# results in a smaller module than using either alone.
168EU_STRIP = $(shell which eu-strip || echo true)
169
170quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@
171 cmd_sign_ko_stripped_ko_unsigned = \
172 cp $< $@ && \
173 strip -x -g $@ && \
174 $(EU_STRIP) $@
175
176ifeq ($(SIGN_MODULES),1)
177
178quiet_cmd_genkeyid = GENKEYID $@
179 cmd_genkeyid = \
180 perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid
181
182%.signer %.keyid: %
183 $(call if_changed,genkeyid)
184
185KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid
186quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@
187 cmd_sign_ko_ko_stripped = \
188 sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@
189else
190KEYRING_DEP :=
191quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@
192 cmd_sign_ko_ko_unsigned = \
193 cp $< $@
194endif
195
196$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE
197 $(call if_changed,sign_ko_ko_stripped)
198
199$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE
200 $(call if_changed,sign_ko_stripped_ko_unsigned)
201
202targets += $(modules)
203endif
129 204
130# Add FORCE to the prequisites of a target to force it to be always rebuilt. 205# Add FORCE to the prequisites of a target to force it to be always rebuilt.
131# --------------------------------------------------------------------------- 206# ---------------------------------------------------------------------------
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c
new file mode 100644
index 000000000000..db0e5cd34c70
--- /dev/null
+++ b/scripts/asn1_compiler.c
@@ -0,0 +1,1545 @@
1/* Simplified ASN.1 notation parser
2 *
3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <stdarg.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <string.h>
17#include <ctype.h>
18#include <unistd.h>
19#include <fcntl.h>
20#include <sys/stat.h>
21#include <linux/asn1_ber_bytecode.h>
22
23enum token_type {
24 DIRECTIVE_ABSENT,
25 DIRECTIVE_ALL,
26 DIRECTIVE_ANY,
27 DIRECTIVE_APPLICATION,
28 DIRECTIVE_AUTOMATIC,
29 DIRECTIVE_BEGIN,
30 DIRECTIVE_BIT,
31 DIRECTIVE_BMPString,
32 DIRECTIVE_BOOLEAN,
33 DIRECTIVE_BY,
34 DIRECTIVE_CHARACTER,
35 DIRECTIVE_CHOICE,
36 DIRECTIVE_CLASS,
37 DIRECTIVE_COMPONENT,
38 DIRECTIVE_COMPONENTS,
39 DIRECTIVE_CONSTRAINED,
40 DIRECTIVE_CONTAINING,
41 DIRECTIVE_DEFAULT,
42 DIRECTIVE_DEFINED,
43 DIRECTIVE_DEFINITIONS,
44 DIRECTIVE_EMBEDDED,
45 DIRECTIVE_ENCODED,
46 DIRECTIVE_ENCODING_CONTROL,
47 DIRECTIVE_END,
48 DIRECTIVE_ENUMERATED,
49 DIRECTIVE_EXCEPT,
50 DIRECTIVE_EXPLICIT,
51 DIRECTIVE_EXPORTS,
52 DIRECTIVE_EXTENSIBILITY,
53 DIRECTIVE_EXTERNAL,
54 DIRECTIVE_FALSE,
55 DIRECTIVE_FROM,
56 DIRECTIVE_GeneralString,
57 DIRECTIVE_GeneralizedTime,
58 DIRECTIVE_GraphicString,
59 DIRECTIVE_IA5String,
60 DIRECTIVE_IDENTIFIER,
61 DIRECTIVE_IMPLICIT,
62 DIRECTIVE_IMPLIED,
63 DIRECTIVE_IMPORTS,
64 DIRECTIVE_INCLUDES,
65 DIRECTIVE_INSTANCE,
66 DIRECTIVE_INSTRUCTIONS,
67 DIRECTIVE_INTEGER,
68 DIRECTIVE_INTERSECTION,
69 DIRECTIVE_ISO646String,
70 DIRECTIVE_MAX,
71 DIRECTIVE_MIN,
72 DIRECTIVE_MINUS_INFINITY,
73 DIRECTIVE_NULL,
74 DIRECTIVE_NumericString,
75 DIRECTIVE_OBJECT,
76 DIRECTIVE_OCTET,
77 DIRECTIVE_OF,
78 DIRECTIVE_OPTIONAL,
79 DIRECTIVE_ObjectDescriptor,
80 DIRECTIVE_PATTERN,
81 DIRECTIVE_PDV,
82 DIRECTIVE_PLUS_INFINITY,
83 DIRECTIVE_PRESENT,
84 DIRECTIVE_PRIVATE,
85 DIRECTIVE_PrintableString,
86 DIRECTIVE_REAL,
87 DIRECTIVE_RELATIVE_OID,
88 DIRECTIVE_SEQUENCE,
89 DIRECTIVE_SET,
90 DIRECTIVE_SIZE,
91 DIRECTIVE_STRING,
92 DIRECTIVE_SYNTAX,
93 DIRECTIVE_T61String,
94 DIRECTIVE_TAGS,
95 DIRECTIVE_TRUE,
96 DIRECTIVE_TeletexString,
97 DIRECTIVE_UNION,
98 DIRECTIVE_UNIQUE,
99 DIRECTIVE_UNIVERSAL,
100 DIRECTIVE_UTCTime,
101 DIRECTIVE_UTF8String,
102 DIRECTIVE_UniversalString,
103 DIRECTIVE_VideotexString,
104 DIRECTIVE_VisibleString,
105 DIRECTIVE_WITH,
106 NR__DIRECTIVES,
107 TOKEN_ASSIGNMENT = NR__DIRECTIVES,
108 TOKEN_OPEN_CURLY,
109 TOKEN_CLOSE_CURLY,
110 TOKEN_OPEN_SQUARE,
111 TOKEN_CLOSE_SQUARE,
112 TOKEN_OPEN_ACTION,
113 TOKEN_CLOSE_ACTION,
114 TOKEN_COMMA,
115 TOKEN_NUMBER,
116 TOKEN_TYPE_NAME,
117 TOKEN_ELEMENT_NAME,
118 NR__TOKENS
119};
120
121static const unsigned char token_to_tag[NR__TOKENS] = {
122 /* EOC goes first */
123 [DIRECTIVE_BOOLEAN] = ASN1_BOOL,
124 [DIRECTIVE_INTEGER] = ASN1_INT,
125 [DIRECTIVE_BIT] = ASN1_BTS,
126 [DIRECTIVE_OCTET] = ASN1_OTS,
127 [DIRECTIVE_NULL] = ASN1_NULL,
128 [DIRECTIVE_OBJECT] = ASN1_OID,
129 [DIRECTIVE_ObjectDescriptor] = ASN1_ODE,
130 [DIRECTIVE_EXTERNAL] = ASN1_EXT,
131 [DIRECTIVE_REAL] = ASN1_REAL,
132 [DIRECTIVE_ENUMERATED] = ASN1_ENUM,
133 [DIRECTIVE_EMBEDDED] = 0,
134 [DIRECTIVE_UTF8String] = ASN1_UTF8STR,
135 [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID,
136 /* 14 */
137 /* 15 */
138 [DIRECTIVE_SEQUENCE] = ASN1_SEQ,
139 [DIRECTIVE_SET] = ASN1_SET,
140 [DIRECTIVE_NumericString] = ASN1_NUMSTR,
141 [DIRECTIVE_PrintableString] = ASN1_PRNSTR,
142 [DIRECTIVE_T61String] = ASN1_TEXSTR,
143 [DIRECTIVE_TeletexString] = ASN1_TEXSTR,
144 [DIRECTIVE_VideotexString] = ASN1_VIDSTR,
145 [DIRECTIVE_IA5String] = ASN1_IA5STR,
146 [DIRECTIVE_UTCTime] = ASN1_UNITIM,
147 [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM,
148 [DIRECTIVE_GraphicString] = ASN1_GRASTR,
149 [DIRECTIVE_VisibleString] = ASN1_VISSTR,
150 [DIRECTIVE_GeneralString] = ASN1_GENSTR,
151 [DIRECTIVE_UniversalString] = ASN1_UNITIM,
152 [DIRECTIVE_CHARACTER] = ASN1_CHRSTR,
153 [DIRECTIVE_BMPString] = ASN1_BMPSTR,
154};
155
156static const char asn1_classes[4][5] = {
157 [ASN1_UNIV] = "UNIV",
158 [ASN1_APPL] = "APPL",
159 [ASN1_CONT] = "CONT",
160 [ASN1_PRIV] = "PRIV"
161};
162
163static const char asn1_methods[2][5] = {
164 [ASN1_UNIV] = "PRIM",
165 [ASN1_APPL] = "CONS"
166};
167
168static const char *const asn1_universal_tags[32] = {
169 "EOC",
170 "BOOL",
171 "INT",
172 "BTS",
173 "OTS",
174 "NULL",
175 "OID",
176 "ODE",
177 "EXT",
178 "REAL",
179 "ENUM",
180 "EPDV",
181 "UTF8STR",
182 "RELOID",
183 NULL, /* 14 */
184 NULL, /* 15 */
185 "SEQ",
186 "SET",
187 "NUMSTR",
188 "PRNSTR",
189 "TEXSTR",
190 "VIDSTR",
191 "IA5STR",
192 "UNITIM",
193 "GENTIM",
194 "GRASTR",
195 "VISSTR",
196 "GENSTR",
197 "UNISTR",
198 "CHRSTR",
199 "BMPSTR",
200 NULL /* 31 */
201};
202
203static const char *filename;
204static const char *grammar_name;
205static const char *outputname;
206static const char *headername;
207
208static const char *const directives[NR__DIRECTIVES] = {
209#define _(X) [DIRECTIVE_##X] = #X
210 _(ABSENT),
211 _(ALL),
212 _(ANY),
213 _(APPLICATION),
214 _(AUTOMATIC),
215 _(BEGIN),
216 _(BIT),
217 _(BMPString),
218 _(BOOLEAN),
219 _(BY),
220 _(CHARACTER),
221 _(CHOICE),
222 _(CLASS),
223 _(COMPONENT),
224 _(COMPONENTS),
225 _(CONSTRAINED),
226 _(CONTAINING),
227 _(DEFAULT),
228 _(DEFINED),
229 _(DEFINITIONS),
230 _(EMBEDDED),
231 _(ENCODED),
232 [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
233 _(END),
234 _(ENUMERATED),
235 _(EXCEPT),
236 _(EXPLICIT),
237 _(EXPORTS),
238 _(EXTENSIBILITY),
239 _(EXTERNAL),
240 _(FALSE),
241 _(FROM),
242 _(GeneralString),
243 _(GeneralizedTime),
244 _(GraphicString),
245 _(IA5String),
246 _(IDENTIFIER),
247 _(IMPLICIT),
248 _(IMPLIED),
249 _(IMPORTS),
250 _(INCLUDES),
251 _(INSTANCE),
252 _(INSTRUCTIONS),
253 _(INTEGER),
254 _(INTERSECTION),
255 _(ISO646String),
256 _(MAX),
257 _(MIN),
258 [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
259 [DIRECTIVE_NULL] = "NULL",
260 _(NumericString),
261 _(OBJECT),
262 _(OCTET),
263 _(OF),
264 _(OPTIONAL),
265 _(ObjectDescriptor),
266 _(PATTERN),
267 _(PDV),
268 [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
269 _(PRESENT),
270 _(PRIVATE),
271 _(PrintableString),
272 _(REAL),
273 [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
274 _(SEQUENCE),
275 _(SET),
276 _(SIZE),
277 _(STRING),
278 _(SYNTAX),
279 _(T61String),
280 _(TAGS),
281 _(TRUE),
282 _(TeletexString),
283 _(UNION),
284 _(UNIQUE),
285 _(UNIVERSAL),
286 _(UTCTime),
287 _(UTF8String),
288 _(UniversalString),
289 _(VideotexString),
290 _(VisibleString),
291 _(WITH)
292};
293
294struct action {
295 struct action *next;
296 unsigned char index;
297 char name[];
298};
299
300static struct action *action_list;
301static unsigned nr_actions;
302
303struct token {
304 unsigned short line;
305 enum token_type token_type : 8;
306 unsigned char size;
307 struct action *action;
308 const char *value;
309 struct type *type;
310};
311
312static struct token *token_list;
313static unsigned nr_tokens;
314
315static int directive_compare(const void *_key, const void *_pdir)
316{
317 const struct token *token = _key;
318 const char *const *pdir = _pdir, *dir = *pdir;
319 size_t dlen, clen;
320 int val;
321
322 dlen = strlen(dir);
323 clen = (dlen < token->size) ? dlen : token->size;
324
325 //printf("cmp(%*.*s,%s) = ",
326 // (int)token->size, (int)token->size, token->value,
327 // dir);
328
329 val = memcmp(token->value, dir, clen);
330 if (val != 0) {
331 //printf("%d [cmp]\n", val);
332 return val;
333 }
334
335 if (dlen == token->size) {
336 //printf("0\n");
337 return 0;
338 }
339 //printf("%d\n", (int)dlen - (int)token->size);
340 return dlen - token->size; /* shorter -> negative */
341}
342
343/*
344 * Tokenise an ASN.1 grammar
345 */
346static void tokenise(char *buffer, char *end)
347{
348 struct token *tokens;
349 char *line, *nl, *p, *q;
350 unsigned tix, lineno;
351
352 /* Assume we're going to have half as many tokens as we have
353 * characters
354 */
355 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
356 if (!tokens) {
357 perror(NULL);
358 exit(1);
359 }
360 tix = 0;
361
362 lineno = 0;
363 while (buffer < end) {
364 /* First of all, break out a line */
365 lineno++;
366 line = buffer;
367 nl = memchr(line, '\n', end - buffer);
368 if (!nl) {
369 buffer = nl = end;
370 } else {
371 buffer = nl + 1;
372 *nl = '\0';
373 }
374
375 /* Remove "--" comments */
376 p = line;
377 next_comment:
378 while ((p = memchr(p, '-', nl - p))) {
379 if (p[1] == '-') {
380 /* Found a comment; see if there's a terminator */
381 q = p + 2;
382 while ((q = memchr(q, '-', nl - q))) {
383 if (q[1] == '-') {
384 /* There is - excise the comment */
385 q += 2;
386 memmove(p, q, nl - q);
387 goto next_comment;
388 }
389 q++;
390 }
391 *p = '\0';
392 nl = p;
393 break;
394 } else {
395 p++;
396 }
397 }
398
399 p = line;
400 while (p < nl) {
401 /* Skip white space */
402 while (p < nl && isspace(*p))
403 *(p++) = 0;
404 if (p >= nl)
405 break;
406
407 tokens[tix].line = lineno;
408 tokens[tix].value = p;
409
410 /* Handle string tokens */
411 if (isalpha(*p)) {
412 const char **dir;
413
414 /* Can be a directive, type name or element
415 * name. Find the end of the name.
416 */
417 q = p + 1;
418 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
419 q++;
420 tokens[tix].size = q - p;
421 p = q;
422
423 /* If it begins with a lowercase letter then
424 * it's an element name
425 */
426 if (islower(tokens[tix].value[0])) {
427 tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
428 continue;
429 }
430
431 /* Otherwise we need to search the directive
432 * table
433 */
434 dir = bsearch(&tokens[tix], directives,
435 sizeof(directives) / sizeof(directives[1]),
436 sizeof(directives[1]),
437 directive_compare);
438 if (dir) {
439 tokens[tix++].token_type = dir - directives;
440 continue;
441 }
442
443 tokens[tix++].token_type = TOKEN_TYPE_NAME;
444 continue;
445 }
446
447 /* Handle numbers */
448 if (isdigit(*p)) {
449 /* Find the end of the number */
450 q = p + 1;
451 while (q < nl && (isdigit(*q)))
452 q++;
453 tokens[tix].size = q - p;
454 p = q;
455 tokens[tix++].token_type = TOKEN_NUMBER;
456 continue;
457 }
458
459 if (nl - p >= 3) {
460 if (memcmp(p, "::=", 3) == 0) {
461 p += 3;
462 tokens[tix].size = 3;
463 tokens[tix++].token_type = TOKEN_ASSIGNMENT;
464 continue;
465 }
466 }
467
468 if (nl - p >= 2) {
469 if (memcmp(p, "({", 2) == 0) {
470 p += 2;
471 tokens[tix].size = 2;
472 tokens[tix++].token_type = TOKEN_OPEN_ACTION;
473 continue;
474 }
475 if (memcmp(p, "})", 2) == 0) {
476 p += 2;
477 tokens[tix].size = 2;
478 tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
479 continue;
480 }
481 }
482
483 if (nl - p >= 1) {
484 tokens[tix].size = 1;
485 switch (*p) {
486 case '{':
487 p += 1;
488 tokens[tix++].token_type = TOKEN_OPEN_CURLY;
489 continue;
490 case '}':
491 p += 1;
492 tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
493 continue;
494 case '[':
495 p += 1;
496 tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
497 continue;
498 case ']':
499 p += 1;
500 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
501 continue;
502 case ',':
503 p += 1;
504 tokens[tix++].token_type = TOKEN_COMMA;
505 continue;
506 default:
507 break;
508 }
509 }
510
511 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
512 filename, lineno, *p);
513 exit(1);
514 }
515 }
516
517 nr_tokens = tix;
518 printf("Extracted %u tokens\n", nr_tokens);
519
520#if 0
521 {
522 int n;
523 for (n = 0; n < nr_tokens; n++)
524 printf("Token %3u: '%*.*s'\n",
525 n,
526 (int)token_list[n].size, (int)token_list[n].size,
527 token_list[n].value);
528 }
529#endif
530}
531
532static void build_type_list(void);
533static void parse(void);
534static void render(FILE *out, FILE *hdr);
535
536/*
537 *
538 */
539int main(int argc, char **argv)
540{
541 struct stat st;
542 ssize_t readlen;
543 FILE *out, *hdr;
544 char *buffer, *p;
545 int fd;
546
547 if (argc != 4) {
548 fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
549 argv[0]);
550 exit(2);
551 }
552
553 filename = argv[1];
554 outputname = argv[2];
555 headername = argv[3];
556
557 fd = open(filename, O_RDONLY);
558 if (fd < 0) {
559 perror(filename);
560 exit(1);
561 }
562
563 if (fstat(fd, &st) < 0) {
564 perror(filename);
565 exit(1);
566 }
567
568 if (!(buffer = malloc(st.st_size + 1))) {
569 perror(NULL);
570 exit(1);
571 }
572
573 if ((readlen = read(fd, buffer, st.st_size)) < 0) {
574 perror(filename);
575 exit(1);
576 }
577
578 if (close(fd) < 0) {
579 perror(filename);
580 exit(1);
581 }
582
583 if (readlen != st.st_size) {
584 fprintf(stderr, "%s: Short read\n", filename);
585 exit(1);
586 }
587
588 p = strrchr(argv[1], '/');
589 p = p ? p + 1 : argv[1];
590 grammar_name = strdup(p);
591 if (!p) {
592 perror(NULL);
593 exit(1);
594 }
595 p = strchr(grammar_name, '.');
596 if (p)
597 *p = '\0';
598
599 buffer[readlen] = 0;
600 tokenise(buffer, buffer + readlen);
601 build_type_list();
602 parse();
603
604 out = fopen(outputname, "w");
605 if (!out) {
606 perror(outputname);
607 exit(1);
608 }
609
610 hdr = fopen(headername, "w");
611 if (!out) {
612 perror(headername);
613 exit(1);
614 }
615
616 render(out, hdr);
617
618 if (fclose(out) < 0) {
619 perror(outputname);
620 exit(1);
621 }
622
623 if (fclose(hdr) < 0) {
624 perror(headername);
625 exit(1);
626 }
627
628 return 0;
629}
630
631enum compound {
632 NOT_COMPOUND,
633 SET,
634 SET_OF,
635 SEQUENCE,
636 SEQUENCE_OF,
637 CHOICE,
638 ANY,
639 TYPE_REF,
640 TAG_OVERRIDE
641};
642
643struct element {
644 struct type *type_def;
645 struct token *name;
646 struct token *type;
647 struct action *action;
648 struct element *children;
649 struct element *next;
650 struct element *render_next;
651 struct element *list_next;
652 uint8_t n_elements;
653 enum compound compound : 8;
654 enum asn1_class class : 8;
655 enum asn1_method method : 8;
656 uint8_t tag;
657 unsigned entry_index;
658 unsigned flags;
659#define ELEMENT_IMPLICIT 0x0001
660#define ELEMENT_EXPLICIT 0x0002
661#define ELEMENT_MARKED 0x0004
662#define ELEMENT_RENDERED 0x0008
663#define ELEMENT_SKIPPABLE 0x0010
664#define ELEMENT_CONDITIONAL 0x0020
665};
666
667struct type {
668 struct token *name;
669 struct token *def;
670 struct element *element;
671 unsigned ref_count;
672 unsigned flags;
673#define TYPE_STOP_MARKER 0x0001
674#define TYPE_BEGIN 0x0002
675};
676
677static struct type *type_list;
678static struct type **type_index;
679static unsigned nr_types;
680
681static int type_index_compare(const void *_a, const void *_b)
682{
683 const struct type *const *a = _a, *const *b = _b;
684
685 if ((*a)->name->size != (*b)->name->size)
686 return (*a)->name->size - (*b)->name->size;
687 else
688 return memcmp((*a)->name->value, (*b)->name->value,
689 (*a)->name->size);
690}
691
692static int type_finder(const void *_key, const void *_ti)
693{
694 const struct token *token = _key;
695 const struct type *const *ti = _ti;
696 const struct type *type = *ti;
697
698 if (token->size != type->name->size)
699 return token->size - type->name->size;
700 else
701 return memcmp(token->value, type->name->value,
702 token->size);
703}
704
705/*
706 * Build up a list of types and a sorted index to that list.
707 */
708static void build_type_list(void)
709{
710 struct type *types;
711 unsigned nr, t, n;
712
713 nr = 0;
714 for (n = 0; n < nr_tokens - 1; n++)
715 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
716 token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
717 nr++;
718
719 if (nr == 0) {
720 fprintf(stderr, "%s: No defined types\n", filename);
721 exit(1);
722 }
723
724 nr_types = nr;
725 types = type_list = calloc(nr + 1, sizeof(type_list[0]));
726 if (!type_list) {
727 perror(NULL);
728 exit(1);
729 }
730 type_index = calloc(nr, sizeof(type_index[0]));
731 if (!type_index) {
732 perror(NULL);
733 exit(1);
734 }
735
736 t = 0;
737 types[t].flags |= TYPE_BEGIN;
738 for (n = 0; n < nr_tokens - 1; n++) {
739 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
740 token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
741 types[t].name = &token_list[n];
742 type_index[t] = &types[t];
743 t++;
744 }
745 }
746 types[t].name = &token_list[n + 1];
747 types[t].flags |= TYPE_STOP_MARKER;
748
749 qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
750
751 printf("Extracted %u types\n", nr_types);
752#if 0
753 for (n = 0; n < nr_types; n++) {
754 struct type *type = type_index[n];
755 printf("- %*.*s\n",
756 (int)type->name->size,
757 (int)type->name->size,
758 type->name->value);
759 }
760#endif
761}
762
763static struct element *parse_type(struct token **_cursor, struct token *stop,
764 struct token *name);
765
766/*
767 * Parse the token stream
768 */
769static void parse(void)
770{
771 struct token *cursor;
772 struct type *type;
773
774 /* Parse one type definition statement at a time */
775 type = type_list;
776 do {
777 cursor = type->name;
778
779 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
780 cursor[1].token_type != TOKEN_ASSIGNMENT)
781 abort();
782 cursor += 2;
783
784 type->element = parse_type(&cursor, type[1].name, NULL);
785 type->element->type_def = type;
786
787 if (cursor != type[1].name) {
788 fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n",
789 filename, cursor->line,
790 (int)cursor->size, (int)cursor->size, cursor->value);
791 exit(1);
792 }
793
794 } while (type++, !(type->flags & TYPE_STOP_MARKER));
795
796 printf("Extracted %u actions\n", nr_actions);
797}
798
799static struct element *element_list;
800
801static struct element *alloc_elem(struct token *type)
802{
803 struct element *e = calloc(1, sizeof(*e));
804 if (!e) {
805 perror(NULL);
806 exit(1);
807 }
808 e->list_next = element_list;
809 element_list = e;
810 return e;
811}
812
813static struct element *parse_compound(struct token **_cursor, struct token *end,
814 int alternates);
815
816/*
817 * Parse one type definition statement
818 */
819static struct element *parse_type(struct token **_cursor, struct token *end,
820 struct token *name)
821{
822 struct element *top, *element;
823 struct action *action, **ppaction;
824 struct token *cursor = *_cursor;
825 struct type **ref;
826 char *p;
827 int labelled = 0, implicit = 0;
828
829 top = element = alloc_elem(cursor);
830 element->class = ASN1_UNIV;
831 element->method = ASN1_PRIM;
832 element->tag = token_to_tag[cursor->token_type];
833 element->name = name;
834
835 /* Extract the tag value if one given */
836 if (cursor->token_type == TOKEN_OPEN_SQUARE) {
837 cursor++;
838 if (cursor >= end)
839 goto overrun_error;
840 switch (cursor->token_type) {
841 case DIRECTIVE_UNIVERSAL:
842 element->class = ASN1_UNIV;
843 cursor++;
844 break;
845 case DIRECTIVE_APPLICATION:
846 element->class = ASN1_APPL;
847 cursor++;
848 break;
849 case TOKEN_NUMBER:
850 element->class = ASN1_CONT;
851 break;
852 case DIRECTIVE_PRIVATE:
853 element->class = ASN1_PRIV;
854 cursor++;
855 break;
856 default:
857 fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
858 filename, cursor->line,
859 (int)cursor->size, (int)cursor->size, cursor->value);
860 exit(1);
861 }
862
863 if (cursor >= end)
864 goto overrun_error;
865 if (cursor->token_type != TOKEN_NUMBER) {
866 fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n",
867 filename, cursor->line,
868 (int)cursor->size, (int)cursor->size, cursor->value);
869 exit(1);
870 }
871
872 element->tag &= ~0x1f;
873 element->tag |= strtoul(cursor->value, &p, 10);
874 if (p - cursor->value != cursor->size)
875 abort();
876 cursor++;
877
878 if (cursor >= end)
879 goto overrun_error;
880 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
881 fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
882 filename, cursor->line,
883 (int)cursor->size, (int)cursor->size, cursor->value);
884 exit(1);
885 }
886 cursor++;
887 if (cursor >= end)
888 goto overrun_error;
889 labelled = 1;
890 }
891
892 /* Handle implicit and explicit markers */
893 if (cursor->token_type == DIRECTIVE_IMPLICIT) {
894 element->flags |= ELEMENT_IMPLICIT;
895 implicit = 1;
896 cursor++;
897 if (cursor >= end)
898 goto overrun_error;
899 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
900 element->flags |= ELEMENT_EXPLICIT;
901 cursor++;
902 if (cursor >= end)
903 goto overrun_error;
904 }
905
906 if (labelled) {
907 if (!implicit)
908 element->method |= ASN1_CONS;
909 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
910 element->children = alloc_elem(cursor);
911 element = element->children;
912 element->class = ASN1_UNIV;
913 element->method = ASN1_PRIM;
914 element->tag = token_to_tag[cursor->token_type];
915 element->name = name;
916 }
917
918 /* Extract the type we're expecting here */
919 element->type = cursor;
920 switch (cursor->token_type) {
921 case DIRECTIVE_ANY:
922 element->compound = ANY;
923 cursor++;
924 break;
925
926 case DIRECTIVE_NULL:
927 case DIRECTIVE_BOOLEAN:
928 case DIRECTIVE_ENUMERATED:
929 case DIRECTIVE_INTEGER:
930 element->compound = NOT_COMPOUND;
931 cursor++;
932 break;
933
934 case DIRECTIVE_EXTERNAL:
935 element->method = ASN1_CONS;
936
937 case DIRECTIVE_BMPString:
938 case DIRECTIVE_GeneralString:
939 case DIRECTIVE_GraphicString:
940 case DIRECTIVE_IA5String:
941 case DIRECTIVE_ISO646String:
942 case DIRECTIVE_NumericString:
943 case DIRECTIVE_PrintableString:
944 case DIRECTIVE_T61String:
945 case DIRECTIVE_TeletexString:
946 case DIRECTIVE_UniversalString:
947 case DIRECTIVE_UTF8String:
948 case DIRECTIVE_VideotexString:
949 case DIRECTIVE_VisibleString:
950 case DIRECTIVE_ObjectDescriptor:
951 case DIRECTIVE_GeneralizedTime:
952 case DIRECTIVE_UTCTime:
953 element->compound = NOT_COMPOUND;
954 cursor++;
955 break;
956
957 case DIRECTIVE_BIT:
958 case DIRECTIVE_OCTET:
959 element->compound = NOT_COMPOUND;
960 cursor++;
961 if (cursor >= end)
962 goto overrun_error;
963 if (cursor->token_type != DIRECTIVE_STRING)
964 goto parse_error;
965 cursor++;
966 break;
967
968 case DIRECTIVE_OBJECT:
969 element->compound = NOT_COMPOUND;
970 cursor++;
971 if (cursor >= end)
972 goto overrun_error;
973 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
974 goto parse_error;
975 cursor++;
976 break;
977
978 case TOKEN_TYPE_NAME:
979 element->compound = TYPE_REF;
980 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
981 type_finder);
982 if (!ref) {
983 fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
984 filename, cursor->line,
985 (int)cursor->size, (int)cursor->size, cursor->value);
986 exit(1);
987 }
988 cursor->type = *ref;
989 (*ref)->ref_count++;
990 cursor++;
991 break;
992
993 case DIRECTIVE_CHOICE:
994 element->compound = CHOICE;
995 cursor++;
996 element->children = parse_compound(&cursor, end, 1);
997 break;
998
999 case DIRECTIVE_SEQUENCE:
1000 element->compound = SEQUENCE;
1001 element->method = ASN1_CONS;
1002 cursor++;
1003 if (cursor >= end)
1004 goto overrun_error;
1005 if (cursor->token_type == DIRECTIVE_OF) {
1006 element->compound = SEQUENCE_OF;
1007 cursor++;
1008 if (cursor >= end)
1009 goto overrun_error;
1010 element->children = parse_type(&cursor, end, NULL);
1011 } else {
1012 element->children = parse_compound(&cursor, end, 0);
1013 }
1014 break;
1015
1016 case DIRECTIVE_SET:
1017 element->compound = SET;
1018 element->method = ASN1_CONS;
1019 cursor++;
1020 if (cursor >= end)
1021 goto overrun_error;
1022 if (cursor->token_type == DIRECTIVE_OF) {
1023 element->compound = SET_OF;
1024 cursor++;
1025 if (cursor >= end)
1026 goto parse_error;
1027 element->children = parse_type(&cursor, end, NULL);
1028 } else {
1029 element->children = parse_compound(&cursor, end, 1);
1030 }
1031 break;
1032
1033 default:
1034 fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
1035 filename, cursor->line,
1036 (int)cursor->size, (int)cursor->size, cursor->value);
1037 exit(1);
1038 }
1039
1040 /* Handle elements that are optional */
1041 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1042 cursor->token_type == DIRECTIVE_DEFAULT)
1043 ) {
1044 cursor++;
1045 top->flags |= ELEMENT_SKIPPABLE;
1046 }
1047
1048 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1049 cursor++;
1050 if (cursor >= end)
1051 goto overrun_error;
1052 if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1053 fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
1054 filename, cursor->line,
1055 (int)cursor->size, (int)cursor->size, cursor->value);
1056 exit(1);
1057 }
1058
1059 action = malloc(sizeof(struct action) + cursor->size + 1);
1060 if (!action) {
1061 perror(NULL);
1062 exit(1);
1063 }
1064 action->index = 0;
1065 memcpy(action->name, cursor->value, cursor->size);
1066 action->name[cursor->size] = 0;
1067
1068 for (ppaction = &action_list;
1069 *ppaction;
1070 ppaction = &(*ppaction)->next
1071 ) {
1072 int cmp = strcmp(action->name, (*ppaction)->name);
1073 if (cmp == 0) {
1074 free(action);
1075 action = *ppaction;
1076 goto found;
1077 }
1078 if (cmp < 0) {
1079 action->next = *ppaction;
1080 *ppaction = action;
1081 nr_actions++;
1082 goto found;
1083 }
1084 }
1085 action->next = NULL;
1086 *ppaction = action;
1087 nr_actions++;
1088 found:
1089
1090 element->action = action;
1091 cursor->action = action;
1092 cursor++;
1093 if (cursor >= end)
1094 goto overrun_error;
1095 if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1096 fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
1097 filename, cursor->line,
1098 (int)cursor->size, (int)cursor->size, cursor->value);
1099 exit(1);
1100 }
1101 cursor++;
1102 }
1103
1104 *_cursor = cursor;
1105 return top;
1106
1107parse_error:
1108 fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
1109 filename, cursor->line,
1110 (int)cursor->size, (int)cursor->size, cursor->value);
1111 exit(1);
1112
1113overrun_error:
1114 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1115 exit(1);
1116}
1117
1118/*
1119 * Parse a compound type list
1120 */
1121static struct element *parse_compound(struct token **_cursor, struct token *end,
1122 int alternates)
1123{
1124 struct element *children, **child_p = &children, *element;
1125 struct token *cursor = *_cursor, *name;
1126
1127 if (cursor->token_type != TOKEN_OPEN_CURLY) {
1128 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
1129 filename, cursor->line,
1130 (int)cursor->size, (int)cursor->size, cursor->value);
1131 exit(1);
1132 }
1133 cursor++;
1134 if (cursor >= end)
1135 goto overrun_error;
1136
1137 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1138 fprintf(stderr, "%s:%d: Empty compound\n",
1139 filename, cursor->line);
1140 exit(1);
1141 }
1142
1143 for (;;) {
1144 name = NULL;
1145 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1146 name = cursor;
1147 cursor++;
1148 if (cursor >= end)
1149 goto overrun_error;
1150 }
1151
1152 element = parse_type(&cursor, end, name);
1153 if (alternates)
1154 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1155
1156 *child_p = element;
1157 child_p = &element->next;
1158
1159 if (cursor >= end)
1160 goto overrun_error;
1161 if (cursor->token_type != TOKEN_COMMA)
1162 break;
1163 cursor++;
1164 if (cursor >= end)
1165 goto overrun_error;
1166 }
1167
1168 children->flags &= ~ELEMENT_CONDITIONAL;
1169
1170 if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1171 fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
1172 filename, cursor->line,
1173 (int)cursor->size, (int)cursor->size, cursor->value);
1174 exit(1);
1175 }
1176 cursor++;
1177
1178 *_cursor = cursor;
1179 return children;
1180
1181overrun_error:
1182 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1183 exit(1);
1184}
1185
1186static void render_element(FILE *out, struct element *e, struct element *tag);
1187static void render_out_of_line_list(FILE *out);
1188
1189static int nr_entries;
1190static int render_depth = 1;
1191static struct element *render_list, **render_list_p = &render_list;
1192
1193__attribute__((format(printf, 2, 3)))
1194static void render_opcode(FILE *out, const char *fmt, ...)
1195{
1196 va_list va;
1197
1198 if (out) {
1199 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1200 va_start(va, fmt);
1201 vfprintf(out, fmt, va);
1202 va_end(va);
1203 }
1204 nr_entries++;
1205}
1206
1207__attribute__((format(printf, 2, 3)))
1208static void render_more(FILE *out, const char *fmt, ...)
1209{
1210 va_list va;
1211
1212 if (out) {
1213 va_start(va, fmt);
1214 vfprintf(out, fmt, va);
1215 va_end(va);
1216 }
1217}
1218
1219/*
1220 * Render the grammar into a state machine definition.
1221 */
1222static void render(FILE *out, FILE *hdr)
1223{
1224 struct element *e;
1225 struct action *action;
1226 struct type *root;
1227 int index;
1228
1229 fprintf(hdr, "/*\n");
1230 fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
1231 fprintf(hdr, " *\n");
1232 fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1233 fprintf(hdr, " */\n");
1234 fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1235 fprintf(hdr, "\n");
1236 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1237 if (ferror(hdr)) {
1238 perror(headername);
1239 exit(1);
1240 }
1241
1242 fprintf(out, "/*\n");
1243 fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
1244 fprintf(out, " *\n");
1245 fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1246 fprintf(out, " */\n");
1247 fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1248 fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name);
1249 fprintf(out, "\n");
1250 if (ferror(out)) {
1251 perror(outputname);
1252 exit(1);
1253 }
1254
1255 /* Tabulate the action functions we might have to call */
1256 fprintf(hdr, "\n");
1257 index = 0;
1258 for (action = action_list; action; action = action->next) {
1259 action->index = index++;
1260 fprintf(hdr,
1261 "extern int %s(void *, size_t, unsigned char,"
1262 " const void *, size_t);\n",
1263 action->name);
1264 }
1265 fprintf(hdr, "\n");
1266
1267 fprintf(out, "enum %s_actions {\n", grammar_name);
1268 for (action = action_list; action; action = action->next)
1269 fprintf(out, "\tACT_%s = %u,\n",
1270 action->name, action->index);
1271 fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1272 fprintf(out, "};\n");
1273
1274 fprintf(out, "\n");
1275 fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1276 grammar_name, grammar_name);
1277 for (action = action_list; action; action = action->next)
1278 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1279 fprintf(out, "};\n");
1280
1281 if (ferror(out)) {
1282 perror(outputname);
1283 exit(1);
1284 }
1285
1286 /* We do two passes - the first one calculates all the offsets */
1287 printf("Pass 1\n");
1288 nr_entries = 0;
1289 root = &type_list[0];
1290 render_element(NULL, root->element, NULL);
1291 render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1292 render_out_of_line_list(NULL);
1293
1294 for (e = element_list; e; e = e->list_next)
1295 e->flags &= ~ELEMENT_RENDERED;
1296
1297 /* And then we actually render */
1298 printf("Pass 2\n");
1299 fprintf(out, "\n");
1300 fprintf(out, "static const unsigned char %s_machine[] = {\n",
1301 grammar_name);
1302
1303 nr_entries = 0;
1304 root = &type_list[0];
1305 render_element(out, root->element, NULL);
1306 render_opcode(out, "ASN1_OP_COMPLETE,\n");
1307 render_out_of_line_list(out);
1308
1309 fprintf(out, "};\n");
1310
1311 fprintf(out, "\n");
1312 fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1313 fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1314 fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1315 fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1316 fprintf(out, "};\n");
1317}
1318
1319/*
1320 * Render the out-of-line elements
1321 */
1322static void render_out_of_line_list(FILE *out)
1323{
1324 struct element *e, *ce;
1325 const char *act;
1326 int entry;
1327
1328 while ((e = render_list)) {
1329 render_list = e->render_next;
1330 if (!render_list)
1331 render_list_p = &render_list;
1332
1333 render_more(out, "\n");
1334 e->entry_index = entry = nr_entries;
1335 render_depth++;
1336 for (ce = e->children; ce; ce = ce->next)
1337 render_element(out, ce, NULL);
1338 render_depth--;
1339
1340 act = e->action ? "_ACT" : "";
1341 switch (e->compound) {
1342 case SEQUENCE:
1343 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1344 break;
1345 case SEQUENCE_OF:
1346 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1347 render_opcode(out, "_jump_target(%u),\n", entry);
1348 break;
1349 case SET:
1350 render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1351 break;
1352 case SET_OF:
1353 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1354 render_opcode(out, "_jump_target(%u),\n", entry);
1355 break;
1356 }
1357 if (e->action)
1358 render_opcode(out, "_action(ACT_%s),\n",
1359 e->action->name);
1360 render_opcode(out, "ASN1_OP_RETURN,\n");
1361 }
1362}
1363
1364/*
1365 * Render an element.
1366 */
1367static void render_element(FILE *out, struct element *e, struct element *tag)
1368{
1369 struct element *ec;
1370 const char *cond, *act;
1371 int entry, skippable = 0, outofline = 0;
1372
1373 if (e->flags & ELEMENT_SKIPPABLE ||
1374 (tag && tag->flags & ELEMENT_SKIPPABLE))
1375 skippable = 1;
1376
1377 if ((e->type_def && e->type_def->ref_count > 1) ||
1378 skippable)
1379 outofline = 1;
1380
1381 if (e->type_def && out) {
1382 render_more(out, "\t// %*.*s\n",
1383 (int)e->type_def->name->size, (int)e->type_def->name->size,
1384 e->type_def->name->value);
1385 }
1386
1387 /* Render the operation */
1388 cond = (e->flags & ELEMENT_CONDITIONAL ||
1389 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1390 act = e->action ? "_ACT" : "";
1391 switch (e->compound) {
1392 case ANY:
1393 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
1394 if (e->name)
1395 render_more(out, "\t\t// %*.*s",
1396 (int)e->name->size, (int)e->name->size,
1397 e->name->value);
1398 render_more(out, "\n");
1399 goto dont_render_tag;
1400
1401 case TAG_OVERRIDE:
1402 render_element(out, e->children, e);
1403 return;
1404
1405 case SEQUENCE:
1406 case SEQUENCE_OF:
1407 case SET:
1408 case SET_OF:
1409 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1410 cond,
1411 outofline ? "_JUMP" : "",
1412 skippable ? "_OR_SKIP" : "");
1413 break;
1414
1415 case CHOICE:
1416 goto dont_render_tag;
1417
1418 case TYPE_REF:
1419 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1420 goto dont_render_tag;
1421 default:
1422 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1423 cond, act,
1424 skippable ? "_OR_SKIP" : "");
1425 break;
1426 }
1427
1428 if (e->name)
1429 render_more(out, "\t\t// %*.*s",
1430 (int)e->name->size, (int)e->name->size,
1431 e->name->value);
1432 render_more(out, "\n");
1433
1434 /* Render the tag */
1435 if (!tag)
1436 tag = e;
1437 if (tag->class == ASN1_UNIV &&
1438 tag->tag != 14 &&
1439 tag->tag != 15 &&
1440 tag->tag != 31)
1441 render_opcode(out, "_tag(%s, %s, %s),\n",
1442 asn1_classes[tag->class],
1443 asn1_methods[tag->method | e->method],
1444 asn1_universal_tags[tag->tag]);
1445 else
1446 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1447 asn1_classes[tag->class],
1448 asn1_methods[tag->method | e->method],
1449 tag->tag);
1450 tag = NULL;
1451dont_render_tag:
1452
1453 /* Deal with compound types */
1454 switch (e->compound) {
1455 case TYPE_REF:
1456 render_element(out, e->type->type->element, tag);
1457 if (e->action)
1458 render_opcode(out, "ASN1_OP_ACT,\n");
1459 break;
1460
1461 case SEQUENCE:
1462 if (outofline) {
1463 /* Render out-of-line for multiple use or
1464 * skipability */
1465 render_opcode(out, "_jump_target(%u),", e->entry_index);
1466 if (e->type_def && e->type_def->name)
1467 render_more(out, "\t\t// --> %*.*s",
1468 (int)e->type_def->name->size,
1469 (int)e->type_def->name->size,
1470 e->type_def->name->value);
1471 render_more(out, "\n");
1472 if (!(e->flags & ELEMENT_RENDERED)) {
1473 e->flags |= ELEMENT_RENDERED;
1474 *render_list_p = e;
1475 render_list_p = &e->render_next;
1476 }
1477 return;
1478 } else {
1479 /* Render inline for single use */
1480 render_depth++;
1481 for (ec = e->children; ec; ec = ec->next)
1482 render_element(out, ec, NULL);
1483 render_depth--;
1484 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1485 }
1486 break;
1487
1488 case SEQUENCE_OF:
1489 case SET_OF:
1490 if (outofline) {
1491 /* Render out-of-line for multiple use or
1492 * skipability */
1493 render_opcode(out, "_jump_target(%u),", e->entry_index);
1494 if (e->type_def && e->type_def->name)
1495 render_more(out, "\t\t// --> %*.*s",
1496 (int)e->type_def->name->size,
1497 (int)e->type_def->name->size,
1498 e->type_def->name->value);
1499 render_more(out, "\n");
1500 if (!(e->flags & ELEMENT_RENDERED)) {
1501 e->flags |= ELEMENT_RENDERED;
1502 *render_list_p = e;
1503 render_list_p = &e->render_next;
1504 }
1505 return;
1506 } else {
1507 /* Render inline for single use */
1508 entry = nr_entries;
1509 render_depth++;
1510 render_element(out, e->children, NULL);
1511 render_depth--;
1512 if (e->compound == SEQUENCE_OF)
1513 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1514 else
1515 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1516 render_opcode(out, "_jump_target(%u),\n", entry);
1517 }
1518 break;
1519
1520 case SET:
1521 /* I can't think of a nice way to do SET support without having
1522 * a stack of bitmasks to make sure no element is repeated.
1523 * The bitmask has also to be checked that no non-optional
1524 * elements are left out whilst not preventing optional
1525 * elements from being left out.
1526 */
1527 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1528 exit(1);
1529
1530 case CHOICE:
1531 for (ec = e->children; ec; ec = ec->next)
1532 render_element(out, ec, NULL);
1533 if (!skippable)
1534 render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1535 if (e->action)
1536 render_opcode(out, "ASN1_OP_ACT,\n");
1537 break;
1538
1539 default:
1540 break;
1541 }
1542
1543 if (e->action)
1544 render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1545}
diff --git a/scripts/sign-file b/scripts/sign-file
new file mode 100644
index 000000000000..e58e34e50ac5
--- /dev/null
+++ b/scripts/sign-file
@@ -0,0 +1,115 @@
1#!/bin/sh
2#
3# Sign a module file using the given key.
4#
5# Format: sign-file <key> <x509> <src-file> <dst-file>
6#
7
8scripts=`dirname $0`
9
10CONFIG_MODULE_SIG_SHA512=y
11if [ -r .config ]
12then
13 . ./.config
14fi
15
16key="$1"
17x509="$2"
18src="$3"
19dst="$4"
20
21if [ ! -r "$key" ]
22then
23 echo "Can't read private key" >&2
24 exit 2
25fi
26
27if [ ! -r "$x509" ]
28then
29 echo "Can't read X.509 certificate" >&2
30 exit 2
31fi
32if [ ! -r "$x509.signer" ]
33then
34 echo "Can't read Signer name" >&2
35 exit 2;
36fi
37if [ ! -r "$x509.keyid" ]
38then
39 echo "Can't read Key identifier" >&2
40 exit 2;
41fi
42
43#
44# Signature parameters
45#
46algo=1 # Public-key crypto algorithm: RSA
47hash= # Digest algorithm
48id_type=1 # Identifier type: X.509
49
50#
51# Digest the data
52#
53dgst=
54if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ]
55then
56 prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14"
57 dgst=-sha1
58 hash=2
59elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ]
60then
61 prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C"
62 dgst=-sha224
63 hash=7
64elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ]
65then
66 prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20"
67 dgst=-sha256
68 hash=4
69elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ]
70then
71 prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30"
72 dgst=-sha384
73 hash=5
74elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ]
75then
76 prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40"
77 dgst=-sha512
78 hash=6
79else
80 echo "$0: Can't determine hash algorithm" >&2
81 exit 2
82fi
83
84(
85perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $?
86openssl dgst $dgst -binary $src || exit $?
87) >$src.dig || exit $?
88
89#
90# Generate the binary signature, which will be just the integer that comprises
91# the signature with no metadata attached.
92#
93openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $?
94signerlen=`stat -c %s $x509.signer`
95keyidlen=`stat -c %s $x509.keyid`
96siglen=`stat -c %s $src.sig`
97
98#
99# Build the signed binary
100#
101(
102 cat $src || exit $?
103 echo '~Module signature appended~' || exit $?
104 cat $x509.signer $x509.keyid || exit $?
105
106 # Preface each signature integer with a 2-byte BE length
107 perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $?
108 cat $src.sig || exit $?
109
110 # Generate the information block
111 perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $?
112) >$dst~ || exit $?
113
114# Permit in-place signing
115mv $dst~ $dst || exit $?
diff --git a/scripts/x509keyid b/scripts/x509keyid
new file mode 100755
index 000000000000..c8e91a4af385
--- /dev/null
+++ b/scripts/x509keyid
@@ -0,0 +1,268 @@
1#!/usr/bin/perl -w
2#
3# Generate an identifier from an X.509 certificate that can be placed in a
4# module signature to indentify the key to use.
5#
6# Format:
7#
8# ./scripts/x509keyid <x509-cert> <signer's-name> <key-id>
9#
10# We read the DER-encoded X509 certificate and parse it to extract the Subject
11# name and Subject Key Identifier. The provide the data we need to build the
12# certificate identifier.
13#
14# The signer's name part of the identifier is fabricated from the commonName,
15# the organizationName or the emailAddress components of the X.509 subject
16# name and written to the second named file.
17#
18# The subject key ID to select which of that signer's certificates we're
19# intending to use to sign the module is written to the third named file.
20#
21use strict;
22
23my $raw_data;
24
25die "Need three filenames\n" if ($#ARGV != 2);
26
27my $src = $ARGV[0];
28
29open(FD, "<$src") || die $src;
30binmode FD;
31my @st = stat(FD);
32die $src if (!@st);
33read(FD, $raw_data, $st[7]) || die $src;
34close(FD);
35
36my $UNIV = 0 << 6;
37my $APPL = 1 << 6;
38my $CONT = 2 << 6;
39my $PRIV = 3 << 6;
40
41my $CONS = 0x20;
42
43my $BOOLEAN = 0x01;
44my $INTEGER = 0x02;
45my $BIT_STRING = 0x03;
46my $OCTET_STRING = 0x04;
47my $NULL = 0x05;
48my $OBJ_ID = 0x06;
49my $UTF8String = 0x0c;
50my $SEQUENCE = 0x10;
51my $SET = 0x11;
52my $UTCTime = 0x17;
53my $GeneralizedTime = 0x18;
54
55my %OIDs = (
56 pack("CCC", 85, 4, 3) => "commonName",
57 pack("CCC", 85, 4, 6) => "countryName",
58 pack("CCC", 85, 4, 10) => "organizationName",
59 pack("CCC", 85, 4, 11) => "organizationUnitName",
60 pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption",
61 pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption",
62 pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress",
63 pack("CCC", 85, 29, 35) => "authorityKeyIdentifier",
64 pack("CCC", 85, 29, 14) => "subjectKeyIdentifier",
65 pack("CCC", 85, 29, 19) => "basicConstraints"
66);
67
68###############################################################################
69#
70# Extract an ASN.1 element from a string and return information about it.
71#
72###############################################################################
73sub asn1_extract($$@)
74{
75 my ($cursor, $expected_tag, $optional) = @_;
76
77 return [ -1 ]
78 if ($cursor->[1] == 0 && $optional);
79
80 die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n"
81 if ($cursor->[1] < 2);
82
83 my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2));
84
85 if ($expected_tag != -1 && $tag != $expected_tag) {
86 return [ -1 ]
87 if ($optional);
88 die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag,
89 " not ", $expected_tag, ")\n";
90 }
91
92 $cursor->[0] += 2;
93 $cursor->[1] -= 2;
94
95 die $src, ": ", $cursor->[0], ": ASN.1 long tag\n"
96 if (($tag & 0x1f) == 0x1f);
97 die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n"
98 if ($len == 0x80);
99
100 if ($len > 0x80) {
101 my $l = $len - 0x80;
102 die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n"
103 if ($cursor->[1] < $l);
104
105 if ($l == 0x1) {
106 $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
107 } elsif ($l = 0x2) {
108 $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
109 } elsif ($l = 0x3) {
110 $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
111 $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
112 } elsif ($l = 0x4) {
113 $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
114 } else {
115 die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
116 }
117
118 $cursor->[0] += $l;
119 $cursor->[1] -= $l;
120 }
121
122 die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n"
123 if ($cursor->[1] < $len);
124
125 my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ];
126 $cursor->[0] += $len;
127 $cursor->[1] -= $len;
128
129 return $ret;
130}
131
132###############################################################################
133#
134# Retrieve the data referred to by a cursor
135#
136###############################################################################
137sub asn1_retrieve($)
138{
139 my ($cursor) = @_;
140 my ($offset, $len, $data) = @$cursor;
141 return substr($$data, $offset, $len);
142}
143
144###############################################################################
145#
146# Roughly parse the X.509 certificate
147#
148###############################################################################
149my $cursor = [ 0, length($raw_data), \$raw_data ];
150
151my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE);
152my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE);
153my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1);
154my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER);
155my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
156my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
157my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
158my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
159my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
160my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1);
161my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1);
162my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1);
163
164my $subject_key_id = ();
165my $authority_key_id = ();
166
167#
168# Parse the extension list
169#
170if ($extension_list->[0] != -1) {
171 my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE);
172
173 while ($extensions->[1]->[1] > 0) {
174 my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE);
175 my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID);
176 my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1);
177 my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING);
178
179 my $raw_oid = asn1_retrieve($x_oid->[1]);
180 next if (!exists($OIDs{$raw_oid}));
181 my $x_type = $OIDs{$raw_oid};
182
183 my $raw_value = asn1_retrieve($x_val->[1]);
184
185 if ($x_type eq "subjectKeyIdentifier") {
186 my $vcursor = [ 0, length($raw_value), \$raw_value ];
187
188 $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING);
189 }
190 }
191}
192
193###############################################################################
194#
195# Determine what we're going to use as the signer's name. In order of
196# preference, take one of: commonName, organizationName or emailAddress.
197#
198###############################################################################
199my $org = "";
200my $cn = "";
201my $email = "";
202
203while ($subject->[1]->[1] > 0) {
204 my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET);
205 my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE);
206 my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID);
207 my $n_val = asn1_extract($attr->[1], -1);
208
209 my $raw_oid = asn1_retrieve($n_oid->[1]);
210 next if (!exists($OIDs{$raw_oid}));
211 my $n_type = $OIDs{$raw_oid};
212
213 my $raw_value = asn1_retrieve($n_val->[1]);
214
215 if ($n_type eq "organizationName") {
216 $org = $raw_value;
217 } elsif ($n_type eq "commonName") {
218 $cn = $raw_value;
219 } elsif ($n_type eq "emailAddress") {
220 $email = $raw_value;
221 }
222}
223
224my $id_name = $email;
225
226if ($org && $cn) {
227 # Don't use the organizationName if the commonName repeats it
228 if (length($org) <= length($cn) &&
229 substr($cn, 0, length($org)) eq $org) {
230 $id_name = $cn;
231 goto got_id_name;
232 }
233
234 # Or a signifcant chunk of it
235 if (length($org) >= 7 &&
236 length($cn) >= 7 &&
237 substr($cn, 0, 7) eq substr($org, 0, 7)) {
238 $id_name = $cn;
239 goto got_id_name;
240 }
241
242 $id_name = $org . ": " . $cn;
243} elsif ($org) {
244 $id_name = $org;
245} elsif ($cn) {
246 $id_name = $cn;
247}
248
249got_id_name:
250
251###############################################################################
252#
253# Output the signer's name and the key identifier that we're going to include
254# in module signatures.
255#
256###############################################################################
257die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
258 if (!$subject_key_id);
259
260my $id_key_id = asn1_retrieve($subject_key_id->[1]);
261
262open(OUTFD, ">$ARGV[1]") || die $ARGV[1];
263print OUTFD $id_name;
264close OUTFD || die $ARGV[1];
265
266open(OUTFD, ">$ARGV[2]") || die $ARGV[2];
267print OUTFD $id_key_id;
268close OUTFD || die $ARGV[2];