xref: /openssl/crypto/objects/obj_dat.pl (revision 7ed6de99)
1#! /usr/bin/env perl
2# Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9use integer;
10use strict;
11use warnings;
12use FindBin;
13use lib "$FindBin::Bin/../../util/perl";
14use OpenSSL::copyright;
15
16# Generate the DER encoding for the given OID.
17sub der_it
18{
19    # Prologue
20    my ($v) = @_;
21    my @a = split(/\s+/, $v);
22    my $ret = pack("C*", $a[0] * 40 + $a[1]);
23    shift @a;
24    shift @a;
25
26    # Loop over rest of bytes; or in 0x80 for multi-byte numbers.
27    my $t;
28    foreach (@a) {
29        my @r = ();
30        $t = 0;
31        while ($_ >= 128) {
32            my $x = $_ % 128;
33            $_ /= 128;
34            push(@r, ($t++ ? 0x80 : 0) | $x);
35        }
36        push(@r, ($t++ ? 0x80 : 0) | $_);
37        $ret .= pack("C*", reverse(@r));
38    }
39    return $ret;
40}
41
42# The year the output file is generated.
43my $YEAR = OpenSSL::copyright::latest(($0, $ARGV[0]));
44
45# Read input, parse all #define's into OID name and value.
46# Populate %ln and %sn with long and short names (%dupln and %dupsn)
47# are used to watch for duplicates.  Also %nid and %obj get the
48# NID and OBJ entries.
49my %ln;
50my %sn;
51my %dupln;
52my %dupsn;
53my %nid;
54my %obj;
55my %objd;
56open(IN, "$ARGV[0]") || die "Can't open input file $ARGV[0], $!";
57while (<IN>) {
58    next unless /^\#define\s+(\S+)\s+(.*)$/;
59    my $v = $1;
60    my $d = $2;
61    $d =~ s/^\"//;
62    $d =~ s/\"$//;
63    if ($v =~ /^SN_(.*)$/) {
64        if (defined $dupsn{$d}) {
65            print "WARNING: Duplicate short name \"$d\"\n";
66        } else {
67            $dupsn{$d} = 1;
68        }
69        $sn{$1} = $d;
70    }
71    elsif ($v =~ /^LN_(.*)$/) {
72        if (defined $dupln{$d}) {
73            print "WARNING: Duplicate long name \"$d\"\n";
74        } else {
75            $dupln{$d} = 1;
76        }
77        $ln{$1} = $d;
78    }
79    elsif ($v =~ /^NID_(.*)$/) {
80        $nid{$d} = $1;
81    }
82    elsif ($v =~ /^OBJ_(.*)$/) {
83        $obj{$1} = $v;
84        $objd{$v} = $d;
85    }
86}
87close IN;
88
89# For every value in %obj, recursively expand OBJ_xxx values.  That is:
90#     #define OBJ_iso 1L
91#     #define OBJ_identified_organization OBJ_iso,3L
92# Modify %objd values in-place.  Create an %objn array that has
93my $changed;
94do {
95    $changed = 0;
96    foreach my $k (keys %objd) {
97        $changed = 1 if $objd{$k} =~ s/(OBJ_[^,]+),/$objd{$1},/;
98    }
99} while ($changed);
100
101my @a = sort { $a <=> $b } keys %nid;
102my $n = $a[$#a] + 1;
103my @lvalues = ();
104my $lvalues = 0;
105
106# Scan all defined objects, building up the @out array.
107# %obj_der holds the DER encoding as an array of bytes, and %obj_len
108# holds the length in bytes.
109my @out;
110my %obj_der;
111my %obj_len;
112for (my $i = 0; $i < $n; $i++) {
113    if (!defined $nid{$i}) {
114        push(@out, "    { NULL, NULL, NID_undef },\n");
115        next;
116    }
117
118    my $sn = defined $sn{$nid{$i}} ? "$sn{$nid{$i}}" : "NULL";
119    my $ln = defined $ln{$nid{$i}} ? "$ln{$nid{$i}}" : "NULL";
120    if ($sn eq "NULL") {
121        $sn = $ln;
122        $sn{$nid{$i}} = $ln;
123    }
124    if ($ln eq "NULL") {
125        $ln = $sn;
126        $ln{$nid{$i}} = $sn;
127    }
128
129    my $out = "    {\"$sn\", \"$ln\", NID_$nid{$i}";
130    if (defined $obj{$nid{$i}} && $objd{$obj{$nid{$i}}} =~ /,/) {
131        my $v = $objd{$obj{$nid{$i}}};
132        $v =~ s/L//g;
133        $v =~ s/,/ /g;
134        my $r = &der_it($v);
135        my $z = "";
136        my $length = 0;
137        # Format using fixed-width because we use strcmp later.
138        foreach (unpack("C*",$r)) {
139            $z .= sprintf("0x%02X,", $_);
140            $length++;
141        }
142        $obj_der{$obj{$nid{$i}}} = $z;
143        $obj_len{$obj{$nid{$i}}} = $length;
144
145        push(@lvalues,
146            sprintf("    %-45s  /* [%5d] %s */\n",
147                $z, $lvalues, $obj{$nid{$i}}));
148        $out .= ", $length, &so[$lvalues]";
149        $lvalues += $length;
150    }
151    $out .= "},\n";
152    push(@out, $out);
153}
154
155# Finally ready to generate the output.
156print <<"EOF";
157/*
158 * WARNING: do not edit!
159 * Generated by crypto/objects/obj_dat.pl
160 *
161 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
162 * Licensed under the Apache License 2.0 (the "License").  You may not use
163 * this file except in compliance with the License.  You can obtain a copy
164 * in the file LICENSE in the source distribution or at
165 * https://www.openssl.org/source/license.html
166 */
167
168EOF
169
170print "/* Serialized OID's */\n";
171printf "static const unsigned char so[%d] = {\n", $lvalues + 1;
172print @lvalues;
173print "};\n\n";
174
175printf "#define NUM_NID %d\n", $n;
176printf "static const ASN1_OBJECT nid_objs[NUM_NID] = {\n";
177print @out;
178print  "};\n\n";
179
180{
181    no warnings "uninitialized";
182    @a = grep(defined $sn{$nid{$_}}, 0 .. $n);
183}
184printf "#define NUM_SN %d\n", $#a + 1;
185printf "static const unsigned int sn_objs[NUM_SN] = {\n";
186foreach (sort { $sn{$nid{$a}} cmp $sn{$nid{$b}} } @a) {
187    printf "    %4d,    /* \"$sn{$nid{$_}}\" */\n", $_;
188}
189print  "};\n\n";
190
191{
192    no warnings "uninitialized";
193    @a = grep(defined $ln{$nid{$_}}, 0 .. $n);
194}
195printf "#define NUM_LN %d\n", $#a + 1;
196printf "static const unsigned int ln_objs[NUM_LN] = {\n";
197foreach (sort { $ln{$nid{$a}} cmp $ln{$nid{$b}} } @a) {
198    printf "    %4d,    /* \"$ln{$nid{$_}}\" */\n", $_;
199}
200print  "};\n\n";
201
202{
203    no warnings "uninitialized";
204    @a = grep(defined $obj{$nid{$_}}, 0 .. $n);
205}
206printf "#define NUM_OBJ %d\n", $#a + 1;
207printf "static const unsigned int obj_objs[NUM_OBJ] = {\n";
208
209# Compare DER; prefer shorter; if some length, use the "smaller" encoding.
210sub obj_cmp
211{
212    no warnings "uninitialized";
213    my $A = $obj_len{$obj{$nid{$a}}};
214    my $B = $obj_len{$obj{$nid{$b}}};
215    my $r = $A - $B;
216    return $r if $r != 0;
217
218    $A = $obj_der{$obj{$nid{$a}}};
219    $B = $obj_der{$obj{$nid{$b}}};
220    return $A cmp $B;
221}
222foreach (sort obj_cmp @a) {
223    my $m = $obj{$nid{$_}};
224    my $v = $objd{$m};
225    $v =~ s/L//g;
226    $v =~ s/,/ /g;
227    printf "    %4d,    /* %-32s %s */\n", $_, $m, $v;
228}
229print  "};\n";
230