You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
3.0 KiB

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