1 #! /usr/bin/env python3 2 3 """ 4 This script should be called *manually* when we want to upgrade SSLError 5 `library` and `reason` mnemnonics to a more recent OpenSSL version. 6 7 It takes two arguments: 8 - the path to the OpenSSL source tree (e.g. git checkout) 9 - the path to the C file to be generated 10 (probably Modules/_ssl_data.h) 11 """ 12 13 import datetime 14 import os 15 import re 16 import sys 17 import _ssl 18 19 20 def parse_error_codes(h_file, prefix, libcode): 21 pat = re.compile(r"#define\W+(%s([\w]+))\W+(\d+)\b" % re.escape(prefix)) 22 codes = [] 23 with open(h_file, "r", encoding="latin1") as f: 24 for line in f: 25 match = pat.search(line) 26 if match: 27 code, name, num = match.groups() 28 num = int(num) 29 # e.g. ("SSL_R_BAD_DATA", ("ERR_LIB_SSL", "BAD_DATA", 390)) 30 codes.append((code, (libcode, name, num))) 31 return codes 32 33 if __name__ == "__main__": 34 openssl_inc = sys.argv[1] 35 outfile = sys.argv[2] 36 use_stdout = outfile == '-' 37 f = sys.stdout if use_stdout else open(outfile, "w") 38 error_libraries = { 39 # mnemonic -> (library code, error prefix, header file) 40 'PEM': ('ERR_LIB_PEM', 'PEM_R_', 'crypto/pem/pem.h'), 41 'SSL': ('ERR_LIB_SSL', 'SSL_R_', 'ssl/ssl.h'), 42 'X509': ('ERR_LIB_X509', 'X509_R_', 'crypto/x509/x509.h'), 43 } 44 45 # Read codes from libraries 46 new_codes = [] 47 for libcode, prefix, h_file in sorted(error_libraries.values()): 48 new_codes += parse_error_codes(os.path.join(openssl_inc, h_file), 49 prefix, libcode) 50 new_code_nums = set((libcode, num) 51 for (code, (libcode, name, num)) in new_codes) 52 53 # Merge with existing codes (in case some old codes disappeared). 54 codes = {} 55 for errname, (libnum, errnum) in _ssl.err_names_to_codes.items(): 56 lib = error_libraries[_ssl.lib_codes_to_names[libnum]] 57 libcode = lib[0] # e.g. ERR_LIB_PEM 58 errcode = lib[1] + errname # e.g. SSL_R_BAD_SSL_SESSION_ID_LENGTH 59 # Only keep it if the numeric codes weren't reused 60 if (libcode, errnum) not in new_code_nums: 61 codes[errcode] = libcode, errname, errnum 62 codes.update(dict(new_codes)) 63 64 def w(l): 65 f.write(l + "\n") 66 w("/* File generated by Tools/ssl/make_ssl_data.py */") 67 w("/* Generated on %s */" % datetime.datetime.now().isoformat()) 68 w("") 69 70 w("static struct py_ssl_library_code library_codes[] = {") 71 for mnemo, (libcode, _, _) in sorted(error_libraries.items()): 72 w(' {"%s", %s},' % (mnemo, libcode)) 73 w(' { NULL }') 74 w('};') 75 w("") 76 77 w("static struct py_ssl_error_code error_codes[] = {") 78 for errcode, (libcode, name, num) in sorted(codes.items()): 79 w(' #ifdef %s' % (errcode)) 80 w(' {"%s", %s, %s},' % (name, libcode, errcode)) 81 w(' #else') 82 w(' {"%s", %s, %d},' % (name, libcode, num)) 83 w(' #endif') 84 w(' { NULL }') 85 w('};') 86 if not use_stdout: 87 f.close() 88