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