17db96d56Sopenharmony_ci#! /usr/bin/env python3 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci""" 47db96d56Sopenharmony_ciThis script should be called *manually* when we want to upgrade SSLError 57db96d56Sopenharmony_ci`library` and `reason` mnemonics to a more recent OpenSSL version. 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ciIt takes two arguments: 87db96d56Sopenharmony_ci- the path to the OpenSSL source tree (e.g. git checkout) 97db96d56Sopenharmony_ci- the path to the header file to be generated Modules/_ssl_data_{version}.h 107db96d56Sopenharmony_ci- error codes are version specific 117db96d56Sopenharmony_ci""" 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ciimport argparse 147db96d56Sopenharmony_ciimport datetime 157db96d56Sopenharmony_ciimport operator 167db96d56Sopenharmony_ciimport os 177db96d56Sopenharmony_ciimport re 187db96d56Sopenharmony_ciimport sys 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ciparser = argparse.ArgumentParser( 227db96d56Sopenharmony_ci description="Generate ssl_data.h from OpenSSL sources" 237db96d56Sopenharmony_ci) 247db96d56Sopenharmony_ciparser.add_argument("srcdir", help="OpenSSL source directory") 257db96d56Sopenharmony_ciparser.add_argument( 267db96d56Sopenharmony_ci "output", nargs="?", type=argparse.FileType("w"), default=sys.stdout 277db96d56Sopenharmony_ci) 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_cidef _file_search(fname, pat): 317db96d56Sopenharmony_ci with open(fname, encoding="utf-8") as f: 327db96d56Sopenharmony_ci for line in f: 337db96d56Sopenharmony_ci match = pat.search(line) 347db96d56Sopenharmony_ci if match is not None: 357db96d56Sopenharmony_ci yield match 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_cidef parse_err_h(args): 397db96d56Sopenharmony_ci """Parse err codes, e.g. ERR_LIB_X509: 11""" 407db96d56Sopenharmony_ci pat = re.compile(r"#\s*define\W+ERR_LIB_(\w+)\s+(\d+)") 417db96d56Sopenharmony_ci lib2errnum = {} 427db96d56Sopenharmony_ci for match in _file_search(args.err_h, pat): 437db96d56Sopenharmony_ci libname, num = match.groups() 447db96d56Sopenharmony_ci lib2errnum[libname] = int(num) 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci return lib2errnum 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_cidef parse_openssl_error_text(args): 507db96d56Sopenharmony_ci """Parse error reasons, X509_R_AKID_MISMATCH""" 517db96d56Sopenharmony_ci # ignore backslash line continuation for now 527db96d56Sopenharmony_ci pat = re.compile(r"^((\w+?)_R_(\w+)):(\d+):") 537db96d56Sopenharmony_ci for match in _file_search(args.errtxt, pat): 547db96d56Sopenharmony_ci reason, libname, errname, num = match.groups() 557db96d56Sopenharmony_ci if "_F_" in reason: 567db96d56Sopenharmony_ci # ignore function codes 577db96d56Sopenharmony_ci continue 587db96d56Sopenharmony_ci num = int(num) 597db96d56Sopenharmony_ci yield reason, libname, errname, num 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_cidef parse_extra_reasons(args): 637db96d56Sopenharmony_ci """Parse extra reasons from openssl.ec""" 647db96d56Sopenharmony_ci pat = re.compile(r"^R\s+((\w+)_R_(\w+))\s+(\d+)") 657db96d56Sopenharmony_ci for match in _file_search(args.errcodes, pat): 667db96d56Sopenharmony_ci reason, libname, errname, num = match.groups() 677db96d56Sopenharmony_ci num = int(num) 687db96d56Sopenharmony_ci yield reason, libname, errname, num 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_cidef gen_library_codes(args): 727db96d56Sopenharmony_ci """Generate table short libname to numeric code""" 737db96d56Sopenharmony_ci yield "static struct py_ssl_library_code library_codes[] = {" 747db96d56Sopenharmony_ci for libname in sorted(args.lib2errnum): 757db96d56Sopenharmony_ci yield f"#ifdef ERR_LIB_{libname}" 767db96d56Sopenharmony_ci yield f' {{"{libname}", ERR_LIB_{libname}}},' 777db96d56Sopenharmony_ci yield "#endif" 787db96d56Sopenharmony_ci yield " { NULL }" 797db96d56Sopenharmony_ci yield "};" 807db96d56Sopenharmony_ci yield "" 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_cidef gen_error_codes(args): 847db96d56Sopenharmony_ci """Generate error code table for error reasons""" 857db96d56Sopenharmony_ci yield "static struct py_ssl_error_code error_codes[] = {" 867db96d56Sopenharmony_ci for reason, libname, errname, num in args.reasons: 877db96d56Sopenharmony_ci yield f" #ifdef {reason}" 887db96d56Sopenharmony_ci yield f' {{"{errname}", ERR_LIB_{libname}, {reason}}},' 897db96d56Sopenharmony_ci yield " #else" 907db96d56Sopenharmony_ci yield f' {{"{errname}", {args.lib2errnum[libname]}, {num}}},' 917db96d56Sopenharmony_ci yield " #endif" 927db96d56Sopenharmony_ci 937db96d56Sopenharmony_ci yield " { NULL }" 947db96d56Sopenharmony_ci yield "};" 957db96d56Sopenharmony_ci yield "" 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_cidef main(): 997db96d56Sopenharmony_ci args = parser.parse_args() 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci args.err_h = os.path.join(args.srcdir, "include", "openssl", "err.h") 1027db96d56Sopenharmony_ci if not os.path.isfile(args.err_h): 1037db96d56Sopenharmony_ci # Fall back to infile for OpenSSL 3.0.0 1047db96d56Sopenharmony_ci args.err_h += ".in" 1057db96d56Sopenharmony_ci args.errcodes = os.path.join(args.srcdir, "crypto", "err", "openssl.ec") 1067db96d56Sopenharmony_ci args.errtxt = os.path.join(args.srcdir, "crypto", "err", "openssl.txt") 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci if not os.path.isfile(args.errtxt): 1097db96d56Sopenharmony_ci parser.error(f"File {args.errtxt} not found in srcdir\n.") 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ci # {X509: 11, ...} 1127db96d56Sopenharmony_ci args.lib2errnum = parse_err_h(args) 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_ci # [('X509_R_AKID_MISMATCH', 'X509', 'AKID_MISMATCH', 110), ...] 1157db96d56Sopenharmony_ci reasons = [] 1167db96d56Sopenharmony_ci reasons.extend(parse_openssl_error_text(args)) 1177db96d56Sopenharmony_ci reasons.extend(parse_extra_reasons(args)) 1187db96d56Sopenharmony_ci # sort by libname, numeric error code 1197db96d56Sopenharmony_ci args.reasons = sorted(reasons, key=operator.itemgetter(0, 3)) 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci lines = [ 1227db96d56Sopenharmony_ci "/* File generated by Tools/ssl/make_ssl_data.py */" 1237db96d56Sopenharmony_ci f"/* Generated on {datetime.datetime.utcnow().isoformat()} */" 1247db96d56Sopenharmony_ci ] 1257db96d56Sopenharmony_ci lines.extend(gen_library_codes(args)) 1267db96d56Sopenharmony_ci lines.append("") 1277db96d56Sopenharmony_ci lines.extend(gen_error_codes(args)) 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci for line in lines: 1307db96d56Sopenharmony_ci args.output.write(line + "\n") 1317db96d56Sopenharmony_ci 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ciif __name__ == "__main__": 1347db96d56Sopenharmony_ci main() 135