209 lines · plain
1#!/usr/bin/perl -w2# SPDX-License-Identifier: GPL-2.0-or-later3#4# Build a static ASN.1 Object Identified (OID) registry5#6# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.7# Written by David Howells (dhowells@redhat.com)8#9 10use strict;11use Cwd qw(abs_path);12 13my @names = ();14my @oids = ();15 16if ($#ARGV != 1) {17 print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";18 exit(2);19}20 21my $abs_srctree = abs_path($ENV{'srctree'});22 23#24# Open the file to read from25#26open IN_FILE, "<$ARGV[0]" || die;27while (<IN_FILE>) {28 chomp;29 if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) {30 push @names, $1;31 push @oids, $2;32 }33}34close IN_FILE || die;35 36#37# Open the files to write into38#39open C_FILE, ">$ARGV[1]" or die;40print C_FILE "/*\n";41my $scriptname = $0;42$scriptname =~ s#^\Q$abs_srctree/\E##;43print C_FILE " * Automatically generated by ", $scriptname, ". Do not edit\n";44print C_FILE " */\n";45 46#47# Split the data up into separate lists and also determine the lengths of the48# encoded data arrays.49#50my @indices = ();51my @lengths = ();52my $total_length = 0;53 54for (my $i = 0; $i <= $#names; $i++) {55 my $name = $names[$i];56 my $oid = $oids[$i];57 58 my @components = split(/[.]/, $oid);59 60 # Determine the encoded length of this OID61 my $size = $#components;62 for (my $loop = 2; $loop <= $#components; $loop++) {63 my $c = $components[$loop];64 65 # We will base128 encode the number66 my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));67 $tmp = int($tmp / 7);68 $size += $tmp;69 }70 push @lengths, $size;71 push @indices, $total_length;72 $total_length += $size;73}74 75#76# Emit the look-up-by-OID index table77#78print C_FILE "\n";79if ($total_length <= 255) {80 print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n";81} else {82 print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n";83}84for (my $i = 0; $i <= $#names; $i++) {85 print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n"86}87print C_FILE "\t[OID__NR] = ", $total_length, "\n";88print C_FILE "};\n";89 90#91# Encode the OIDs92#93my @encoded_oids = ();94 95for (my $i = 0; $i <= $#names; $i++) {96 my @octets = ();97 98 my @components = split(/[.]/, $oids[$i]);99 100 push @octets, $components[0] * 40 + $components[1];101 102 for (my $loop = 2; $loop <= $#components; $loop++) {103 my $c = $components[$loop];104 105 # Base128 encode the number106 my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));107 $tmp = int($tmp / 7);108 109 for (; $tmp > 0; $tmp--) {110 push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;111 }112 push @octets, $c & 0x7f;113 }114 115 push @encoded_oids, \@octets;116}117 118#119# Create a hash value for each OID120#121my @hash_values = ();122for (my $i = 0; $i <= $#names; $i++) {123 my @octets = @{$encoded_oids[$i]};124 125 my $hash = $#octets;126 foreach (@octets) {127 $hash += $_ * 33;128 }129 130 $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash);131 132 push @hash_values, $hash & 0xff;133}134 135#136# Emit the OID data137#138print C_FILE "\n";139print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n";140for (my $i = 0; $i <= $#names; $i++) {141 my @octets = @{$encoded_oids[$i]};142 print C_FILE "\t";143 print C_FILE $_, ", " foreach (@octets);144 print C_FILE "\t// ", $names[$i];145 print C_FILE "\n";146}147print C_FILE "};\n";148 149#150# Build the search index table (ordered by length then hash then content)151#152my @index_table = ( 0 .. $#names );153 154@index_table = sort {155 my @octets_a = @{$encoded_oids[$a]};156 my @octets_b = @{$encoded_oids[$b]};157 158 return $hash_values[$a] <=> $hash_values[$b]159 if ($hash_values[$a] != $hash_values[$b]);160 return $#octets_a <=> $#octets_b161 if ($#octets_a != $#octets_b);162 for (my $i = $#octets_a; $i >= 0; $i--) {163 return $octets_a[$i] <=> $octets_b[$i]164 if ($octets_a[$i] != $octets_b[$i]);165 }166 return 0;167 168} @index_table;169 170#171# Emit the search index and hash value table172#173print C_FILE "\n";174print C_FILE "static const struct {\n";175print C_FILE "\tunsigned char hash;\n";176if ($#names <= 255) {177 print C_FILE "\tenum OID oid : 8;\n";178} else {179 print C_FILE "\tenum OID oid : 16;\n";180}181print C_FILE "} oid_search_table[OID__NR] = {\n";182for (my $i = 0; $i <= $#names; $i++) {183 my @octets = @{$encoded_oids[$index_table[$i]]};184 printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ",185 $i,186 $hash_values[$index_table[$i]],187 $names[$index_table[$i]]);188 printf C_FILE "%02x", $_ foreach (@octets);189 print C_FILE "\n";190}191print C_FILE "};\n";192 193#194# Emit the OID debugging name table195#196#print C_FILE "\n";197#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n";198#199#for (my $i = 0; $i <= $#names; $i++) {200# print C_FILE "\t\"", $names[$i], "\",\n"201#}202#print C_FILE "\t\"Unknown-OID\"\n";203#print C_FILE "};\n";204 205#206# Polish off207#208close C_FILE or die;209