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