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