obj_dat.pl 6.0 KB
Newer Older
C
code4lala 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
#! /usr/bin/env perl
# Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License").  You may not use
# this file except in compliance with the License.  You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html

use integer;
use strict;
use warnings;

# Generate the DER encoding for the given OID.
sub der_it
{
    # Prologue
    my ($v) = @_;
    my @a = split(/\s+/, $v);
    my $ret = pack("C*", $a[0] * 40 + $a[1]);
    shift @a;
    shift @a;

    # Loop over rest of bytes; or in 0x80 for multi-byte numbers.
    my $t;
    foreach (@a) {
        my @r = ();
        $t = 0;
        while ($_ >= 128) {
            my $x = $_ % 128;
            $_ /= 128;
            push(@r, ($t++ ? 0x80 : 0) | $x);
        }
        push(@r, ($t++ ? 0x80 : 0) | $_);
        $ret .= pack("C*", reverse(@r));
    }
    return $ret;
}

# Output year depends on the year of the script and the input file.
my $YEAR = [localtime([stat($0)]->[9])]->[5] + 1900;
my $iYEAR = [localtime([stat($ARGV[0])]->[9])]->[5] + 1900;
$YEAR = $iYEAR if $iYEAR > $YEAR;

# Read input, parse all #define's into OID name and value.
# Populate %ln and %sn with long and short names (%dupln and %dupsn)
# are used to watch for duplicates.  Also %nid and %obj get the
# NID and OBJ entries.
my %ln;
my %sn;
my %dupln;
my %dupsn;
my %nid;
my %obj;
my %objd;
open(IN, "$ARGV[0]") || die "Can't open input file $ARGV[0], $!";
while (<IN>) {
    next unless /^\#define\s+(\S+)\s+(.*)$/;
    my $v = $1;
    my $d = $2;
    $d =~ s/^\"//;
    $d =~ s/\"$//;
    if ($v =~ /^SN_(.*)$/) {
        if (defined $dupsn{$d}) {
            print "WARNING: Duplicate short name \"$d\"\n";
        } else {
            $dupsn{$d} = 1;
        }
        $sn{$1} = $d;
    }
    elsif ($v =~ /^LN_(.*)$/) {
        if (defined $dupln{$d}) {
            print "WARNING: Duplicate long name \"$d\"\n";
        } else {
            $dupln{$d} = 1;
        }
        $ln{$1} = $d;
    }
    elsif ($v =~ /^NID_(.*)$/) {
        $nid{$d} = $1;
    }
    elsif ($v =~ /^OBJ_(.*)$/) {
        $obj{$1} = $v;
        $objd{$v} = $d;
    }
}
close IN;

# For every value in %obj, recursively expand OBJ_xxx values.  That is:
#     #define OBJ_iso 1L
#     #define OBJ_identified_organization OBJ_iso,3L
# Modify %objd values in-place.  Create an %objn array that has
my $changed;
do {
    $changed = 0;
    foreach my $k (keys %objd) {
        $changed = 1 if $objd{$k} =~ s/(OBJ_[^,]+),/$objd{$1},/;
    }
} while ($changed);

my @a = sort { $a <=> $b } keys %nid;
my $n = $a[$#a] + 1;
my @lvalues = ();
my $lvalues = 0;

# Scan all defined objects, building up the @out array.
# %obj_der holds the DER encoding as an array of bytes, and %obj_len
# holds the length in bytes.
my @out;
my %obj_der;
my %obj_len;
for (my $i = 0; $i < $n; $i++) {
    if (!defined $nid{$i}) {
        push(@out, "    { NULL, NULL, NID_undef },\n");
        next;
    }

    my $sn = defined $sn{$nid{$i}} ? "$sn{$nid{$i}}" : "NULL";
    my $ln = defined $ln{$nid{$i}} ? "$ln{$nid{$i}}" : "NULL";
    if ($sn eq "NULL") {
        $sn = $ln;
        $sn{$nid{$i}} = $ln;
    }
    if ($ln eq "NULL") {
        $ln = $sn;
        $ln{$nid{$i}} = $sn;
    }

    my $out = "    {\"$sn\", \"$ln\", NID_$nid{$i}";
    if (defined $obj{$nid{$i}} && $objd{$obj{$nid{$i}}} =~ /,/) {
        my $v = $objd{$obj{$nid{$i}}};
        $v =~ s/L//g;
        $v =~ s/,/ /g;
        my $r = &der_it($v);
        my $z = "";
        my $length = 0;
        # Format using fixed-with because we use strcmp later.
        foreach (unpack("C*",$r)) {
            $z .= sprintf("0x%02X,", $_);
            $length++;
        }
        $obj_der{$obj{$nid{$i}}} = $z;
        $obj_len{$obj{$nid{$i}}} = $length;

        push(@lvalues,
            sprintf("    %-45s  /* [%5d] %s */\n",
                $z, $lvalues, $obj{$nid{$i}}));
        $out .= ", $length, &so[$lvalues]";
        $lvalues += $length;
    }
    $out .= "},\n";
    push(@out, $out);
}

# Finally ready to generate the output.
print <<"EOF";
/*
 * WARNING: do not edit!
 * Generated by crypto/objects/obj_dat.pl
 *
 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

EOF

print "/* Serialized OID's */\n";
printf "static const unsigned char so[%d] = {\n", $lvalues + 1;
print @lvalues;
print "};\n\n";

printf "#define NUM_NID %d\n", $n;
printf "static const ASN1_OBJECT nid_objs[NUM_NID] = {\n";
print @out;
print  "};\n\n";

{
    no warnings "uninitialized";
    @a = grep(defined $sn{$nid{$_}}, 0 .. $n);
}
printf "#define NUM_SN %d\n", $#a + 1;
printf "static const unsigned int sn_objs[NUM_SN] = {\n";
foreach (sort { $sn{$nid{$a}} cmp $sn{$nid{$b}} } @a) {
    printf "    %4d,    /* \"$sn{$nid{$_}}\" */\n", $_;
}
print  "};\n\n";

{
    no warnings "uninitialized";
    @a = grep(defined $ln{$nid{$_}}, 0 .. $n);
}
printf "#define NUM_LN %d\n", $#a + 1;
printf "static const unsigned int ln_objs[NUM_LN] = {\n";
foreach (sort { $ln{$nid{$a}} cmp $ln{$nid{$b}} } @a) {
    printf "    %4d,    /* \"$ln{$nid{$_}}\" */\n", $_;
}
print  "};\n\n";

{
    no warnings "uninitialized";
    @a = grep(defined $obj{$nid{$_}}, 0 .. $n);
}
printf "#define NUM_OBJ %d\n", $#a + 1;
printf "static const unsigned int obj_objs[NUM_OBJ] = {\n";

# Compare DER; prefer shorter; if some length, use the "smaller" encoding.
sub obj_cmp
{
    no warnings "uninitialized";
    my $A = $obj_len{$obj{$nid{$a}}};
    my $B = $obj_len{$obj{$nid{$b}}};
    my $r = $A - $B;
    return $r if $r != 0;

    $A = $obj_der{$obj{$nid{$a}}};
    $B = $obj_der{$obj{$nid{$b}}};
    return $A cmp $B;
}
foreach (sort obj_cmp @a) {
    my $m = $obj{$nid{$_}};
    my $v = $objd{$m};
    $v =~ s/L//g;
    $v =~ s/,/ /g;
    printf "    %4d,    /* %-32s %s */\n", $_, $m, $v;
}
print  "};\n";