1#!/usr/bin/env perl 2 3# Generate error.c 4# 5# Usage: ./generate_errors.pl or scripts/generate_errors.pl without arguments, 6# or generate_errors.pl include_dir data_dir error_file 7# 8# Copyright The Mbed TLS Contributors 9# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 10# 11# This file is provided under the Apache License 2.0, or the 12# GNU General Public License v2.0 or later. 13# 14# ********** 15# Apache License 2.0: 16# 17# Licensed under the Apache License, Version 2.0 (the "License"); you may 18# not use this file except in compliance with the License. 19# You may obtain a copy of the License at 20# 21# http://www.apache.org/licenses/LICENSE-2.0 22# 23# Unless required by applicable law or agreed to in writing, software 24# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 25# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26# See the License for the specific language governing permissions and 27# limitations under the License. 28# 29# ********** 30# 31# ********** 32# GNU General Public License v2.0 or later: 33# 34# This program is free software; you can redistribute it and/or modify 35# it under the terms of the GNU General Public License as published by 36# the Free Software Foundation; either version 2 of the License, or 37# (at your option) any later version. 38# 39# This program is distributed in the hope that it will be useful, 40# but WITHOUT ANY WARRANTY; without even the implied warranty of 41# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42# GNU General Public License for more details. 43# 44# You should have received a copy of the GNU General Public License along 45# with this program; if not, write to the Free Software Foundation, Inc., 46# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 47# 48# ********** 49 50use strict; 51 52my ($include_dir, $data_dir, $error_file); 53 54if( @ARGV ) { 55 die "Invalid number of arguments" if scalar @ARGV != 3; 56 ($include_dir, $data_dir, $error_file) = @ARGV; 57 58 -d $include_dir or die "No such directory: $include_dir\n"; 59 -d $data_dir or die "No such directory: $data_dir\n"; 60} else { 61 $include_dir = 'include/mbedtls'; 62 $data_dir = 'scripts/data_files'; 63 $error_file = 'library/error.c'; 64 65 unless( -d $include_dir && -d $data_dir ) { 66 chdir '..' or die; 67 -d $include_dir && -d $data_dir 68 or die "Without arguments, must be run from root or scripts\n" 69 } 70} 71 72my $error_format_file = $data_dir.'/error.fmt'; 73 74my @low_level_modules = qw( AES ARC4 ARIA ASN1 BASE64 BIGNUM BLOWFISH 75 CAMELLIA CCM CHACHA20 CHACHAPOLY CMAC CTR_DRBG DES 76 ENTROPY GCM HKDF HMAC_DRBG MD2 MD4 MD5 77 NET OID PADLOCK PBKDF2 PLATFORM POLY1305 RIPEMD160 78 SHA1 SHA256 SHA512 THREADING XTEA ); 79my @high_level_modules = qw( CIPHER DHM ECP MD 80 PEM PK PKCS12 PKCS5 81 RSA SSL X509 ); 82 83my $line_separator = $/; 84undef $/; 85 86open(FORMAT_FILE, "$error_format_file") or die "Opening error format file '$error_format_file': $!"; 87my $error_format = <FORMAT_FILE>; 88close(FORMAT_FILE); 89 90$/ = $line_separator; 91 92my @files = <$include_dir/*.h>; 93my @necessary_include_files; 94my @matches; 95foreach my $file (@files) { 96 open(FILE, "$file"); 97 my @grep_res = grep(/^\s*#define\s+MBEDTLS_ERR_\w+\s+\-0x[0-9A-Fa-f]+/, <FILE>); 98 push(@matches, @grep_res); 99 close FILE; 100 my $include_name = $file; 101 $include_name =~ s!.*/!!; 102 push @necessary_include_files, $include_name if @grep_res; 103} 104 105my $ll_old_define = ""; 106my $hl_old_define = ""; 107 108my $ll_code_check = ""; 109my $hl_code_check = ""; 110 111my $headers = ""; 112my %included_headers; 113 114my %error_codes_seen; 115 116foreach my $line (@matches) 117{ 118 next if ($line =~ /compat-1.2.h/); 119 my ($error_name, $error_code) = $line =~ /(MBEDTLS_ERR_\w+)\s+\-(0x\w+)/; 120 my ($description) = $line =~ /\/\*\*< (.*?)\.? \*\//; 121 122 die "Duplicated error code: $error_code ($error_name)\n" 123 if( $error_codes_seen{$error_code}++ ); 124 125 $description =~ s/\\/\\\\/g; 126 if ($description eq "") { 127 $description = "DESCRIPTION MISSING"; 128 warn "Missing description for $error_name\n"; 129 } 130 131 my ($module_name) = $error_name =~ /^MBEDTLS_ERR_([^_]+)/; 132 133 # Fix faulty ones 134 $module_name = "BIGNUM" if ($module_name eq "MPI"); 135 $module_name = "CTR_DRBG" if ($module_name eq "CTR"); 136 $module_name = "HMAC_DRBG" if ($module_name eq "HMAC"); 137 138 my $define_name = $module_name; 139 $define_name = "X509_USE,X509_CREATE" if ($define_name eq "X509"); 140 $define_name = "ASN1_PARSE" if ($define_name eq "ASN1"); 141 $define_name = "SSL_TLS" if ($define_name eq "SSL"); 142 $define_name = "PEM_PARSE,PEM_WRITE" if ($define_name eq "PEM"); 143 144 my $include_name = $module_name; 145 $include_name =~ tr/A-Z/a-z/; 146 147 # Fix faulty ones 148 $include_name = "net_sockets" if ($module_name eq "NET"); 149 150 $included_headers{"${include_name}.h"} = $module_name; 151 152 my $found_ll = grep $_ eq $module_name, @low_level_modules; 153 my $found_hl = grep $_ eq $module_name, @high_level_modules; 154 if (!$found_ll && !$found_hl) 155 { 156 printf("Error: Do not know how to handle: $module_name\n"); 157 exit 1; 158 } 159 160 my $code_check; 161 my $old_define; 162 my $white_space; 163 my $first; 164 165 if ($found_ll) 166 { 167 $code_check = \$ll_code_check; 168 $old_define = \$ll_old_define; 169 $white_space = ' '; 170 } 171 else 172 { 173 $code_check = \$hl_code_check; 174 $old_define = \$hl_old_define; 175 $white_space = ' '; 176 } 177 178 if ($define_name ne ${$old_define}) 179 { 180 if (${$old_define} ne "") 181 { 182 ${$code_check} .= "#endif /* "; 183 $first = 0; 184 foreach my $dep (split(/,/, ${$old_define})) 185 { 186 ${$code_check} .= " || " if ($first++); 187 ${$code_check} .= "MBEDTLS_${dep}_C"; 188 } 189 ${$code_check} .= " */\n\n"; 190 } 191 192 ${$code_check} .= "#if "; 193 $headers .= "#if " if ($include_name ne ""); 194 $first = 0; 195 foreach my $dep (split(/,/, ${define_name})) 196 { 197 ${$code_check} .= " || " if ($first); 198 $headers .= " || " if ($first++); 199 200 ${$code_check} .= "defined(MBEDTLS_${dep}_C)"; 201 $headers .= "defined(MBEDTLS_${dep}_C)" if 202 ($include_name ne ""); 203 } 204 ${$code_check} .= "\n"; 205 $headers .= "\n#include \"mbedtls/${include_name}.h\"\n". 206 "#endif\n\n" if ($include_name ne ""); 207 ${$old_define} = $define_name; 208 } 209 210 if ($error_name eq "MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE") 211 { 212 ${$code_check} .= "${white_space}if( use_ret == -($error_name) )\n". 213 "${white_space}\{\n". 214 "${white_space} mbedtls_snprintf( buf, buflen, \"$module_name - $description\" );\n". 215 "${white_space} return;\n". 216 "${white_space}}\n" 217 } 218 else 219 { 220 ${$code_check} .= "${white_space}if( use_ret == -($error_name) )\n". 221 "${white_space} mbedtls_snprintf( buf, buflen, \"$module_name - $description\" );\n" 222 } 223}; 224 225if ($ll_old_define ne "") 226{ 227 $ll_code_check .= "#endif /* "; 228 my $first = 0; 229 foreach my $dep (split(/,/, $ll_old_define)) 230 { 231 $ll_code_check .= " || " if ($first++); 232 $ll_code_check .= "MBEDTLS_${dep}_C"; 233 } 234 $ll_code_check .= " */\n"; 235} 236if ($hl_old_define ne "") 237{ 238 $hl_code_check .= "#endif /* "; 239 my $first = 0; 240 foreach my $dep (split(/,/, $hl_old_define)) 241 { 242 $hl_code_check .= " || " if ($first++); 243 $hl_code_check .= "MBEDTLS_${dep}_C"; 244 } 245 $hl_code_check .= " */\n"; 246} 247 248$error_format =~ s/HEADER_INCLUDED\n/$headers/g; 249$error_format =~ s/LOW_LEVEL_CODE_CHECKS\n/$ll_code_check/g; 250$error_format =~ s/HIGH_LEVEL_CODE_CHECKS\n/$hl_code_check/g; 251 252open(ERROR_FILE, ">$error_file") or die "Opening destination file '$error_file': $!"; 253print ERROR_FILE $error_format; 254close(ERROR_FILE); 255 256my $errors = 0; 257for my $include_name (@necessary_include_files) 258{ 259 if (not $included_headers{$include_name}) 260 { 261 print STDERR "The header file \"$include_name\" defines error codes but has not been included!\n"; 262 ++$errors; 263 } 264} 265 266exit !!$errors; 267