Skip to content

Instantly share code, notes, and snippets.

@Lukasa
Last active February 24, 2016 12:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lukasa/dc754d2193c53fdecde2 to your computer and use it in GitHub Desktop.
Save Lukasa/dc754d2193c53fdecde2 to your computer and use it in GitHub Desktop.
Validate certificates on Windows using Crypt32.dll

This file contains code for validating certificates using Window's Crypt32 API, rather than OpenSSL. It's intended to go hand-in-hand with my proposed changes to cryptography that will make these bindings accessible, and will later be productised in the certitude module.

from cryptography.hazmat.bindings.crypt32.binding import lib, ffi
# Raw DER encoded certs. Used for testing purposes only.
CERTS = [
b'0\x82\x04\xed0\x82\x03\xd5\xa0\x03\x02\x01\x02\x02\x10<\x9b\xfd6\xbelQ\xea\xaf!\xb8\x7f\xca\xd2\xdf\xd00\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000_1\x0b0\t\x06\x03U\x04\x06\x13\x02FR1\x0e0\x0c\x06\x03U\x04\x08\x13\x05Paris1\x0e0\x0c\x06\x03U\x04\x07\x13\x05Paris1\x0e0\x0c\x06\x03U\x04\n\x13\x05Gandi1 0\x1e\x06\x03U\x04\x03\x13\x17Gandi Standard SSL CA 20\x1e\x17\r150916000000Z\x17\r180916235959Z0U1!0\x1f\x06\x03U\x04\x0b\x13\x18Domain Control Validated1\x1b0\x19\x06\x03U\x04\x0b\x13\x12Gandi Standard SSL1\x130\x11\x06\x03U\x04\x03\x13\ncertifi.io0\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xc3\xef\xfd\x1c\x89\x88)\x887l\x1b3U\xfd\xb0fH\xdd\xa4@\x90V.J\xc6A\xd3-B\x0b\xec\x00\xd6\x16{\x04\xb3\xae\xb3\x1f\xc01\xa9/\xec\x82\xff]\x02\x96\x1d^\x07K\x9bz\x02M\x08\xa7\x1c$t\xe0\xa4*^\x8c\x11\'\xc66\x0c\x99\xb8`}y\xd1\xed2\x94~\x9e\xd3\xb8D\xafw\x1e\xac\xcb\xe5:g}\x00\xe6#\xcd\xfa\x1do\x8a\xa5\x9e\x14 j\xb4\xd5\x95\x9b\xbbN\x81U\xf1\xa0\xf9\xf4\xc8\xf4\xccC\xeb\xd8\x93m\xa8\x00\\\x06\xdb\xaf\xc1\x0b@\x9f\xf6LH\x86\xee<\xcfs\xbc\xd0~s[\x17\xd0\x9b\x85\xc7\xfa\x171\xb9L\xdfI\xc7:\xee\xf3?)\x05\xaeQ\x04\xe9\xb3\xe7b\xbc\xda\xba@1y.\xc9\x992\x9c\x91\xf1\x94o1\xbak\xdb>\xd1\x99\xc5\xb7\x87 N\xe4\xceA\xd2\xc6yy\xe9\x19\x05\\\xbf\xa0\xf9\xbfeX \xa3\xc8v^\xa2\\\xa8\x85\xdd\x16\xdb\xf8\xf5@f+S\xa7\x7f\xf0a\x87\x15\xb5\xcbN[\xfd\x8fmU\xc9\xc9\x02\x03\x01\x00\x01\xa3\x82\x01\xad0\x82\x01\xa90\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\xb3\x90\xa7\xd8\xc9\xafN\xcda<\x9f|\xad]\x7fA\xfdi0\xea0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14f\xe0\xfa\x8de\xf6\x19Z\xc7\x9a\x94\x95T\xc7\xf1\xdfq\xdd7I0\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x05\xa00\x0c\x06\x03U\x1d\x13\x01\x01\xff\x04\x020\x000\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x020K\x06\x03U\x1d \x04D0B06\x06\x0b+\x06\x01\x04\x01\xb21\x01\x02\x02\x1a0\'0%\x06\x08+\x06\x01\x05\x05\x07\x02\x01\x16\x19https://cps.usertrust.com0\x08\x06\x06g\x81\x0c\x01\x02\x010A\x06\x03U\x1d\x1f\x04:0806\xa04\xa02\x860http://crl.usertrust.com/GandiStandardSSLCA2.crl0s\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04g0e0<\x06\x08+\x06\x01\x05\x05\x070\x02\x860http://crt.usertrust.com/GandiStandardSSLCA2.crt0%\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x19http://ocsp.usertrust.com0%\x06\x03U\x1d\x11\x04\x1e0\x1c\x82\ncertifi.io\x82\x0ewww.certifi.io0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00r\x88&w\x9c@\xc1\xd7\xcc\x1b\xc5a\x90@\x07"\xafnB\xb8\x8e\xfc\xe6<\xef\xc7\xfb-\xb77\xb4v\x0e\xef\xa0I\xc1\xe7i/\xad\x01\xda\xc4\xa7\x86M\xfa\x00\xcd\xaa\xc1\xe2`g\xfam\x89K\x1d{U\xad\x14\x87P?\x8e\x83\xcd\xee\'\x18\x9f\xfc\xb1\xf80,!\xc6E8+B\xa3\xb2\x83\xcbQ\xd1\x87\x06\xe0\x05>\xaa\xc3\x07#\xbfP@-P\xf4i\xb3r6\x14\x01|\xcdAl\x9c\x13\xd4#o\xf09\xac\x8b\x02A\x88-\xd3\xd8\x8b\xec\x99\x0fy\xedN\xac\xad\xbd\x9a\xde~\x174*=\x90JF\x05\x00\xfd\x1a*\xd1\xf2\xe1\xdb\xd6\x94R\xcc(\x00\xfcc\xcbu\xf4q\x89\\\x91\xea\xc0l\x99\x1d\x94vy\x1c\xb8\xdf\xd1\xf0\x95Zl\xed\\&\x0e\xc7\xb2\xa9\x9e\xa7\xc8n_:\xe0\xf8\x91E\x99.\xa8~\xa6\xfe\xa4\x18\x0e\xd2\xf3\xa0\xcdS\xe4q\x05W{#\xb2\x01\x14fL-\xb1q>\xfe\xc1\xf9wz\x00g^\xde\xd0\xaa\'iW\x86\xa2\x0f\xe2O',
b'0\x82\x05\xe90\x82\x03\xd1\xa0\x03\x02\x01\x02\x02\x10\x05\xe4\xdc;\x948\xab;\x85\x97\xcb\xa6\xa1\x98P\xe30\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0c\x05\x000\x81\x881\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\x08\x13\nNew Jersey1\x140\x12\x06\x03U\x04\x07\x13\x0bJersey City1\x1e0\x1c\x06\x03U\x04\n\x13\x15The USERTRUST Network1.0,\x06\x03U\x04\x03\x13%USERTrust RSA Certification Authority0\x1e\x17\r140912000000Z\x17\r240911235959Z0_1\x0b0\t\x06\x03U\x04\x06\x13\x02FR1\x0e0\x0c\x06\x03U\x04\x08\x13\x05Paris1\x0e0\x0c\x06\x03U\x04\x07\x13\x05Paris1\x0e0\x0c\x06\x03U\x04\n\x13\x05Gandi1 0\x1e\x06\x03U\x04\x03\x13\x17Gandi Standard SSL CA 20\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\x94\x04-\xa6y\x95t\xff\xd5\x00<\xf5\xae\xd8\x94\xb1)|\xc0\x8f\x0b\x0b\x89\xb9\x82\x83\x97n7(\xf5\xa2\x1a\xcf\xd2\x92\x0b\x9b\xa8\xd3\x87\x94s\x84\x10\x9f\xdc5\xcb\xc2-\x92\xac!\xb9\xcb;\xfc@\xc1\xc1\x83!\xf0\xbf\xf8\xf6\x9c\xfa\x9c\x82\x10\xc0\xd0\x8eN\xe5\rL\xb0\x91\\\x90\xb4\xa4@Q\x16\xda\xe4\x84\x12-\x05\\\xa1\x1f\x17\x19$Q\xaaz\xea\xe1\x07\x1b\x86\x8d\x01r\xf2\xe7\xd4\x83#9\x9e\xe0\xe1L\x1fk"\xa3\xb4\x10f\xb0\xed\x82\x96\xd7nj\xb4\xf2?\xb5B\xfc\xdd\x8a\xb5\xab\xba-\x1d:u\x9b1\xdc>\x9d\xac[\xd3A\rl\xb0\x1b\xf5:\xf5y\xea!\xa2\xf8\xf43RK$-\x1e\xa4\x99\xb1mH\xbc\xb8\x12\xferp|\xf7\xfb\x02u\xf4\x8d\xde\xd6\xda\xc0\xa02\x1aR\xdf8k.E8??\x04\x96\x00\xfd\xa1\xf4\xa2\xbb\xd5\x17\xd6\'|\x1bXY\x95^\x8a\x12\xfd\x9c\xab\x81>R(HQ\x85k\xf3\x91\xb2\x86?)\xb5n\x03b\xee\xd6\x05\x02\x03\x01\x00\x01\xa3\x82\x01u0\x82\x01q0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14Sy\xbfZ\xaa+J\xcfT\x80\xe1\xd8\x9b\xc0\x9d\xf2\xb2\x03f\xcb0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14\xb3\x90\xa7\xd8\xc9\xafN\xcda<\x9f|\xad]\x7fA\xfdi0\xea0\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\x860\x12\x06\x03U\x1d\x13\x01\x01\xff\x04\x080\x06\x01\x01\xff\x02\x01\x000\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x020"\x06\x03U\x1d \x04\x1b0\x190\r\x06\x0b+\x06\x01\x04\x01\xb21\x01\x02\x02\x1a0\x08\x06\x06g\x81\x0c\x01\x02\x010P\x06\x03U\x1d\x1f\x04I0G0E\xa0C\xa0A\x86?http://crl.usertrust.com/USERTrustRSACertificationAuthority.crl0v\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04j0h0?\x06\x08+\x06\x01\x05\x05\x070\x02\x863http://crt.usertrust.com/USERTrustRSAAddTrustCA.crt0%\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x19http://ocsp.usertrust.com0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0c\x05\x00\x03\x82\x02\x01\x00Xg\xfdr\xb2j\xd7|a\x96\x19~\xd9CF\xd1&}\xc8S\xfaf\xb0k-\xa7\xd3\xaaV\xf7:\x88\xd0;r\xc9P\xfd\xf7Y\xb2\xaah\xf5\x8cs\x03\xbb\x95e\x17\xce/\x1c\xdd\x98\x13\xa2\x91\xc9\xee\xa1@n<\x98\xd6\\\xf3\xb2"<-\xee\x1b\xa4\xe1\xde $\x16\xf2\x8c\x11s\x91:\xf6\xfa\xce$\x02\x87\xca\x93\xec\xb4\xb6\xc8\x16\x17\xc5r\xfc\'@\xf6\x13\xfe\x93\xa6\x9dQ\xef<+\xd8wW\x9b\x8ce:5%6\xb7\xb5\x8aco\x07\'\x93\xb1`\x8d\x80\xdb\x96\xd4z\x8f-\xab\x1c\x88\xc9n~\xd6e\x1f\xaf]\xca\x16?(F\xdc\xa05\xe5\xf9\xe9\xe5\xd5\x96\x88\x0cO\xc6\xb7wgH\x84\'\xb6\x1f\xb0h\xdb\xac\xbfw\xb0\x90\xb8\xa2\xc9\x1c2]\x02\xba%C\x81BG\xbb\xd8\xe1\x8f\x0c\x0cF_\xeeF3k\x03\x14\x82\xd3~\xcd\x8f\xaf\x90\xd6\x8e$}@B\xb4jj\x17\xc6\x95\x97\xe1\xf28\xcd\xa7\xed\xb4\'@\x93\xdfr\xa9\xb8\xc6fc78d"0\xa2;\xf1\xb9\xc8{\xc8\xfb):\xab\x1ar\xd2\x06\x12N\xf6\x82\xd4#o>\xc3\x93\xe5\xd8\xb6\xc0\xde\xdc#\x16\xd6\x130\xb7\xa0\x9a\x0e,U\x06\x00p\x01\xcf\xea9\x1d\x80\xdb\x88\xf7\xa5 \xb8[\xfd1&i\x8f-\na\x83:G\xa6\x13T,\x1e\xe3\xedD\xca\xbcj\x1f(\x0eQ\xd9\xde\x0e\x9fu\xcd\x0e\x03\x95\xca\xf9\xc5\xa9*-\xfeA\xa4\xa1G\xae\r\xc2\xf99f3J[\xe1\x84(Yl}\x94\x17v\xe4E\x82\xadp \xfd\xd2oc\xa8\xd7\xfa\xa03\xfa7\xcb\xf7\xb2e\x9e\xdaPo?\xe4\xa7\xf3\x8e]X2\x97p#.\xe7\xfd\xc4\x15\x9b\x9c\'\x8f2\xed\x17\xadX\x811)\x11\x1a\x9b\xd4\xfcl\x95(\xc7N\x05\x07\xa6\xfd\x1d\xbc\x19\xe2\xe8\xb7\xb9\x11\x8a-p\x12R\x85\x8d\x8c3J\x0f\xfc\x99\x92\xe0cp\xda\xa5\x94Gc\x07\xe7X\xc71_\x05=6U\xfe\x83\xb2\xe8\xa6\xad\xd7\xe9\xe6\x02t\x88t\\\xda4\xdb\x90\xd2mQ\n#\xd6#',
b'0\x82\x05w0\x82\x04_\xa0\x03\x02\x01\x02\x02\x10\x13\xea(p[\xf4\xec\xed\x0c6c\t\x80aC60\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0c\x05\x000o1\x0b0\t\x06\x03U\x04\x06\x13\x02SE1\x140\x12\x06\x03U\x04\n\x13\x0bAddTrust AB1&0$\x06\x03U\x04\x0b\x13\x1dAddTrust External TTP Network1"0 \x06\x03U\x04\x03\x13\x19AddTrust External CA Root0\x1e\x17\r000530104838Z\x17\r200530104838Z0\x81\x881\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\x08\x13\nNew Jersey1\x140\x12\x06\x03U\x04\x07\x13\x0bJersey City1\x1e0\x1c\x06\x03U\x04\n\x13\x15The USERTRUST Network1.0,\x06\x03U\x04\x03\x13%USERTrust RSA Certification Authority0\x82\x02"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x02\x0f\x000\x82\x02\n\x02\x82\x02\x01\x00\x80\x12e\x176\x0e\xc3\xdb\x08\xb3\xd0\xacW\rv\xed\xcd\'\xd3L\xadP\x83a\xe2\xaa M\t-d\t\xdc\xce\x89\x9f\xcc=\xa9\xec\xf6\xcf\xc1\xdc\xf1\xd3\xb1\xd6{7(\x11+G\xda9\xc6\xbc:\x19\xb4_\xa6\xbd}\x9d\xa3cB\xb6v\xf2\xa9;+\x91\xf8\xe2o\xd0\xec\x16 \x90\t>\xe2\xe8t\xc9\x18\xb4\x91\xd4bd\xdb\x7f\xa3\x06\xf1\x88\x18j\x90"<\xbc\xfe\x13\xf0\x87\x14{\xf6\xe4\x1f\x8e\xd4\xe4Q\xc6\x11gF\x08Q\xcb\x86\x14T?\xbc3\xfe~l\x9c\xff\x16\x9d\x18\xbdQ\x8e5\xa6\xa7f\xc8rg\xdb!f\xb1\xd4\x9bx\x03\xc0P:\xe8\xcc\xf0\xdc\xbc\x9eL\xfe\xaf\x05\x965\x1fWZ\xb7\xff\xce\xf9=\xb7,\xb6\xf6T\xdd\xc8\xe7\x12:M\xaeL\x8a\xb7\\\x9a\xb4\xb7 =\xca\x7f"4\xae~;hf\x01D\xe7\x01NFS\x9b3`\xf7\x94\xbeS7\x90sC\xf32\xc3S\xef\xdb\xaa\xfetNi\xc7k\x8c`\x93\xde\xc4\xc7\x0c\xdf\xe12\xae\xcc\x93;Qx\x95g\x8b\xee=V\xfe\x0c\xd0i\x0f\x1b\x0f\xf3%&k3m\xf7nG\xfasC\xe5~\x0e\xa5f\xb1)|2\x84cU\x89\xc4\r\xc1\x93T0\x19\x13\xac\xd3}7\xa7\xeb]:l5\\\xdbA\xd7\x12\xda\xa9I\x0b\xdf\xd8\x80\x8a\t\x93b\x8e\xb5f\xcf%\x88\xcd\x84\xb8\xb1?\xa49\x0f\xd9\x02\x9e\xeb\x12L\x95|\xf3k\x05\xa9^\x16\x83\xcc\xb8g\xe2\xe8\x13\x9d\xcc[\x82\xd3L\xb3\xed[\xff\xde\xe5s\xac#;-\x00\xbf5Ut\tI\xd8IX\x1a\x7f\x926\xe6Q\x92\x0e\xf3&}\x1cM\x17\xbc\xc9\xecC&\xd0\xbfA_@\xa9DD\xf4\x99\xe7W\x87\x9eP\x1fWT\xa8>\xfdtc/\xb1Pe\t\xe6XB.C\x1aL\xb4\xf0%GY\xfa\x04\x1e\x93\xd4&FJP\x81\xb2\xde\xbex\xb7\xfcg\x15\xe1\xc9W\x84\x1e\x0fc\xd6\xe9b\xba\xd6_U.\xea\\\xc6(\x08\x04%9\xb8\x0e+\xa9\xf2L\x97\x1c\x07?\rR\xf5\xed\xef/\x82\x0f\x02\x03\x01\x00\x01\xa3\x81\xf40\x81\xf10\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\xad\xbd\x98z4\xb4&\xf7\xfa\xc4&T\xef\x03\xbd\xe0$\xcbT\x1a0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14Sy\xbfZ\xaa+J\xcfT\x80\xe1\xd8\x9b\xc0\x9d\xf2\xb2\x03f\xcb0\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\x860\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff0\x11\x06\x03U\x1d \x04\n0\x080\x06\x06\x04U\x1d \x000D\x06\x03U\x1d\x1f\x04=0;09\xa07\xa05\x863http://crl.usertrust.com/AddTrustExternalCARoot.crl05\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04)0\'0%\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x19http://ocsp.usertrust.com0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0c\x05\x00\x03\x82\x01\x01\x00\x93e\xf67\x83\x95\x0f^\xc3\x82\x1c\x1f\xd6w\xe7<\x8a\xc0\xaa\t\xf0\xe9\x0b&\xf1\xe0\xc2ju\xa1\xc7y\xc9\xb9R`\xc8)\x12\x0e\xf0\xad\x03\xd6\t\xc4v\xdf\xe5\xa6\x81\x95\xa7F\xda\x82W\xa9\x95\x92\xc5\xb6\x8f\x03"l3w\xc1{2\x17n\x07\xceZ\x14A:\x05$\x1b\xf6\x14\x06;\xa8%$\x0e\xbb\xcc*u\xdd\xb9pA?|\xd0c6!\x07\x1fF\xff`\xa4\x91\xe1g\xbc\xde\x1f~\x19\x14\xc9cg\x91\xeag\x07k\xb4\x8f\x8b\xc0nC}\xc3\xa1\x80l\xb2\x1e\xbcS\x85}\xdc\x90\xa1\xa4\xbc-\xefFrW5\x05\xbf\xbbF\xbbnm7\x99\xb6\xff#\x92\x91\xc6n@\xf8\x8f)V\xea_\xd5_\x14S\xac\xf0Oa\xea\xf7"\xcc\xa7V\x0b\xe2\xb84\x1f&\xd9{\x19\x05h?\xba<\xd48\x06\xa2\xd3\xe6\x8f\x0e\xe3\xb4qm@B\xc5\x84\xb4@\x95+\xf4e\xa0Hy\xf6\x1d\x81c\x96\x9dOu\xe0\xf8|\xe4\x8e\xa9\xd1\xf2\xad\x8a\xb3\x8c\xc7!\xcd\xc2\xef',
]
SERVER_NAME = u"certifi.io"
def build_certificate_context(certs):
"""
Builds a Windows certificate context from a list of DER-encoded certs.
"""
store = lib.CertOpenStore(
lib.CERT_STORE_PROV_MEMORY,
0,
ffi.NULL,
lib.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
ffi.NULL
)
assert store
store = ffi.gc(store, lambda s: lib.CertCloseStore(s, 0))
primary_cert = ffi.new("PCCERT_CONTEXT *")
ok = lib.CertAddEncodedCertificateToStore(
store,
lib.X509_ASN_ENCODING,
certs[0],
len(certs[0]),
lib.CERT_STORE_ADD_ALWAYS,
primary_cert
)
assert ok and primary_cert[0]
primary_cert = ffi.gc(primary_cert, lambda x: lib.CertFreeCertificateContext(x[0]))
for cert in certs[1:]:
ok = lib.CertAddEncodedCertificateToStore(
store,
lib.X509_ASN_ENCODING,
cert,
len(cert),
lib.CERT_STORE_ADD_ALWAYS,
ffi.NULL
)
assert ok
return primary_cert
def test():
assert isinstance(SERVER_NAME, str) # We need a unicode string here.
cert = build_certificate_context(CERTS)
# First, we need to build a certificate chain. This gets Windows
# to see if it can build a chain at all: it says nothing about
# whether the chain is acceptable in this case (e.g. for this
# host).
chain_para = ffi.new("CERT_CHAIN_PARA *")
chain_para[0].cbSize = ffi.sizeof(chain_para[0])
# Extended key usage. We still need to request
# SERVER_GATED_CRYPTO and NETSCAPE because...well,
# because Chrome and IE do.
usage = ffi.new(
"LPCSTR[]",
[
lib.szOID_PKIX_KP_SERVER_AUTH,
lib.szOID_SERVER_GATED_CRYPTO,
lib.szOID_SGC_NETSCAPE,
]
)
chain_para[0].RequestedUsage.dwType = lib.USAGE_MATCH_TYPE_OR
chain_para[0].RequestedUsage.Usage.cUsageIdentifier = 3 # TODO: Programmatically set this!
chain_para[0].RequestedUsage.Usage.rgpszUsageIdentifier = usage
#import pdb; pdb.set_trace()
chain_context = ffi.new("PCCERT_CHAIN_CONTEXT *")
got_chain = lib.CertGetCertificateChain(
ffi.NULL, # chain_engine
cert[0], # certificate
ffi.NULL, # current system time
cert[0][0].hCertStore, # Certificate store
chain_para, # Chain parameters
0, # No flags
ffi.NULL, # Reserved
chain_context,
)
assert got_chain
assert chain_context[0]
chain_context = ffi.gc(chain_context, lambda s: lib.CertFreeCertificateChain(s[0]))
# Next, we need to check that the chain meets our "policy". This is basically:
# is the chain valid for the server in question over TLS?
server_name = ffi.new("wchar_t[]", SERVER_NAME)
extra_policy_para = ffi.new("SSL_EXTRA_CERT_CHAIN_POLICY_PARA *")
extra_policy_para[0].cbSize = ffi.sizeof(extra_policy_para[0])
extra_policy_para[0].dwAuthType = lib.AUTHTYPE_SERVER
extra_policy_para[0].fdwChecks = 0
extra_policy_para[0].pwszServerName = server_name # MUST BE UNICODE
policy_para = ffi.new("CERT_CHAIN_POLICY_PARA *")
policy_para[0].cbSize = ffi.sizeof(policy_para[0])
policy_para[0].dwFlags = 0
policy_para[0].pvExtraPolicyPara = extra_policy_para
policy_status = ffi.new("CERT_CHAIN_POLICY_STATUS *")
policy_status[0].cbSize = ffi.sizeof(policy_status[0])
policy_exists = lib.CertVerifyCertificateChainPolicy(
lib.CERT_CHAIN_POLICY_SSL,
chain_context[0],
policy_para,
policy_status
)
assert policy_exists
# TODO: This is probably overbroad. Look at the errors in https://msdn.microsoft.com/en-us/library/windows/desktop/aa377188(v=vs.85).aspx
# and re-evaluate.
assert not policy_status[0].dwError
test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment