# Temporary sandbox for Python PKCS #8 hacks, probably integrate into # test scripts, libhal.py, etc once have figured this out. # # Both PyCrpto and the Python ecdsa package have their own ASN.1, so # why are we using yet another package? Because it's easier to # understand, that's why. Perhaps once we've debugged this we'll # recode it using one of the other packages to reduce external # dependencies, but for now, pyasn1 wins on ease of debugging. # # Also see the "native" encode and decode routines in pyasn1, which # supposedly encode and decode to built-in Python data types instead # of the fancy types from the pyasn1 library. Might be simpler, but # whole new mess so defer for now. # RFC 5208: PKCS #8 # RFC 2313: PKCS #1.5 [rsa.c] # RFC 5915: EC keys [ecdsa.c] from pyasn1.type.univ import Sequence, SetOf, Integer, OctetString, ObjectIdentifier, BitString, Any from pyasn1.type.namedtype import NamedTypes, NamedType, OptionalNamedType from pyasn1.type.namedval import NamedValues from pyasn1.type.tag import Tag, tagClassContext, tagFormatSimple, tagFormatConstructed from pyasn1.type.constraint import SingleValueConstraint from pyasn1.codec.der.encoder import encode as DER_Encode from pyasn1.codec.der.decoder import decode as DER_Decode from ecdsa import der as ECDSA_DER from ecdsa.util import oid_ecPublicKey, encoded_oid_ecPublicKey from ecdsa.keys import SigningKey from ecdsa.curves import find_curve class AlgorithmIdentifier(Sequence): componentType = NamedTypes( NamedType( "algorithm", ObjectIdentifier()), OptionalNamedType( "parameters", Any())) class AttributeTypeAndValue(Sequence): componentType = NamedTypes( NamedType( "type", ObjectIdentifier()), NamedType( "value", Any())) class Attribute(Sequence): componentType = NamedTypes( NamedType( "type", ObjectIdentifier()), NamedType( "vals", SetOf(componentType = Any()))) # RFC 5208 class PrivateKeyInfo(Sequence): componentType = NamedTypes( NamedType( "version", Integer(namedValues = NamedValues(("v1", 0))) .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(0))), NamedType( "privateKeyAlgorithm", AlgorithmIdentifier()), NamedType( "privateKey", OctetString()), OptionalNamedType( "attributes", SetOf(componentType = Attribute()) .subtype(implicitTag = Tag(tagClassContext, tagFormatConstructed, 0)))) class EncryptedPrivateKeyInfo(Sequence): componentType = NamedTypes( NamedType( "encryptionAlgorithm", AlgorithmIdentifier()), NamedType( "encryptedData", OctetString())) # RFC 2313 class RSAPrivateKey(Sequence): componentType = NamedTypes( NamedType( "version", Integer() .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(0))), NamedType( "n", Integer()), NamedType( "e", Integer()), NamedType( "d", Integer()), NamedType( "p", Integer()), NamedType( "q", Integer()), NamedType( "dP", Integer()), NamedType( "dQ", Integer()), NamedType( "u", Integer())) # RFC 5915 class ECPrivateKey(Sequence): componentType = NamedTypes( NamedType( "version", Integer(namedValues = NamedValues(("ecPrivkeyVer1", 1))) .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(1))), NamedType( "privateKey", OctetString()), OptionalNamedType( "parameters", ObjectIdentifier() .subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 0))), OptionalNamedType( "publicKey", BitString() .subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 1)))) # Test data, generated by OpenSSL der_test_keys = dict( ec_rfc5915 = ''' MHcCAQEEIFWaZOsQxLwZmIK4YAuf1d8S9Pnznvzcl9TjiMpvXkCYoAoGCCqGSM49 AwEHoUQDQgAEC/8vH5bL+3KNNF/NL+VmUKZQtjA59UsGtKP6FP4ZqFc3Y7Gie77/ lG1/L+s/6ircB1JkI8zaE3KYd7s+7IYIEQ== '''.decode("base64"), ec_pkcs8 = ''' MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVZpk6xDEvBmYgrhg C5/V3xL0+fOe/NyX1OOIym9eQJihRANCAAQL/y8flsv7co00X80v5WZQplC2MDn1 Swa0o/oU/hmoVzdjsaJ7vv+UbX8v6z/qKtwHUmQjzNoTcph3uz7shggR '''.decode("base64"), rsa_rfc2313 = ''' MIIEpAIBAAKCAQEAx/N9ee3u6Z6qjw5waPhuUBYy7m6+kRfNYB8KSERGd5K2xD96 IeyvEv+xMDA2BQ3xOummL2yAjtMZ2N7Le37nfpvtzwVWqrOHzq7OWaw/pPl1N9Lq VSQLPoxHw3TVe69QNPVu5SeumaOGXmzTIs1pr2yVBZD/i2KYiif3BO2SgoDx7g4s cFdg/6YiDpKYbY/yx4YN6KJxDGMM6DE0Ih8hE68flJMSIbUWIaJZo0b7XPeE9zYU zf93VLvuYIqWYMuwTw5TSUnzeRq6ALJpf90nObduJsYEPu/i4RFlxdm5WsmOb2Tu F7JFesEdGeT9lCxxd3CI5YTItQIBWsx0AzCS/QIDAQABAoIBAQCmC7Zvwv9cUr8g /cSr52L0bvrstlra8wFCiYRobwp10gilAHHUKlFZXa0vb1ns6J8jZVT0nQ5FjVkx mBMzAzgLFEJwYOaP63ckVFZYcYqI3gBR0312JvCPiL8vuZ5vkC7zS75D3qhIPlwf ng/YHu1dGLbIYJlWjxJN6NJh7Uh1xlZcm0WAJYhJpmMIZJv2abTS4GXw4SVOyMnd tPEgEfrK/y2PsNUPwnby6LR1cE2rxOQtb6gNCov0AAiE0BsJeE7jXa2IEl6lKoBR ChDMAeU53pJPlcYt7ZmAgyezuEfnr4kY5Rk/nTcwTxTpzQi7Dcth8QCRqfu4wXXj QEN7b9cBAoGBAPNjRPc/Z89jYp1IDR+R5oi7YTsLzNAIlS/t9wgrujnVdsm00xos dd+NwvjTi7wE0fV+7u5/W9ni3077JaBGBa9+nD0iB0PgAJW+tb8HUJXABQKoTA4m yyiAHNHgarwc1uwr+yAYqvSj7aAvIcZeXgi3qxDXEOSKuk8n57/TpPMVAoGBANJP /9/6zxd3PdogiP0nC+piJHstexk+l4WRqGWWuRG0VTIEfBk4dQfj/UwfmTcCQxAe D0e9EoHeVOfsv4nfOfDhGC7jHLkLpNJbc5ttgr2sZ6qIouBJ8suMDte/zZze27aU 7epFqw0w9Y58fwRyP2u5ILYFcm+cWeplg9lY4rpJAoGBALzLs1Krn4YzDOr+Whe0 IITN/XVFCQIStk8wo2B2MwXrvTJoDx0Ngf4AxE4qIwmdH5T0erkMmB5jK1/j12MF DiH874tIWyRenXWLMwZU0UDoa7qM/Do6A3uOLUzsbT8wi9M1pp5WJD6S7qBED0oG J6FRf+QXQCZYKn9+b/nQXfKlAoGADwFuPEjk5cO4Qgv4OjfC/eIqwC8qjU6N+RW/ ciAi7ER1n6/6OsJwdzOpKvlGMUqUBl5esLuoymNWo4Wc1PV8aNdmplHGBt3x0KB9 yyUxIt9eNiixllcwX52KoZIp1XuBKbHOl9yIq9RGcPgpB+Qu6jy3PMV+uL/rGnJL ygIxiyECgYAwSLLuxHKGcy+oZo1vxSQlY2gOkprqK9VwjAhxGuGlJftXrL/Dkbxs GatW0bGAyQ+VPivPl8YYhs34NCA1t1pJKczcNbHEJFN57x6AtCbHFLWB91wY96yA 6y/Bgd45PoXryQl7+GdOAPyEYY3mq3R5vaozTraPrnD+61kpKVLJ/Q== '''.decode("base64"), rsa_pkcs8 = ''' MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDH83157e7pnqqP DnBo+G5QFjLubr6RF81gHwpIREZ3krbEP3oh7K8S/7EwMDYFDfE66aYvbICO0xnY 3st7fud+m+3PBVaqs4fOrs5ZrD+k+XU30upVJAs+jEfDdNV7r1A09W7lJ66Zo4Ze bNMizWmvbJUFkP+LYpiKJ/cE7ZKCgPHuDixwV2D/piIOkphtj/LHhg3oonEMYwzo MTQiHyETrx+UkxIhtRYholmjRvtc94T3NhTN/3dUu+5gipZgy7BPDlNJSfN5GroA sml/3Sc5t24mxgQ+7+LhEWXF2blayY5vZO4XskV6wR0Z5P2ULHF3cIjlhMi1AgFa zHQDMJL9AgMBAAECggEBAKYLtm/C/1xSvyD9xKvnYvRu+uy2WtrzAUKJhGhvCnXS CKUAcdQqUVldrS9vWezonyNlVPSdDkWNWTGYEzMDOAsUQnBg5o/rdyRUVlhxioje AFHTfXYm8I+Ivy+5nm+QLvNLvkPeqEg+XB+eD9ge7V0YtshgmVaPEk3o0mHtSHXG VlybRYAliEmmYwhkm/ZptNLgZfDhJU7Iyd208SAR+sr/LY+w1Q/CdvLotHVwTavE 5C1vqA0Ki/QACITQGwl4TuNdrYgSXqUqgFEKEMwB5Tnekk+Vxi3tmYCDJ7O4R+ev iRjlGT+dNzBPFOnNCLsNy2HxAJGp+7jBdeNAQ3tv1wECgYEA82NE9z9nz2NinUgN H5HmiLthOwvM0AiVL+33CCu6OdV2ybTTGix1343C+NOLvATR9X7u7n9b2eLfTvsl oEYFr36cPSIHQ+AAlb61vwdQlcAFAqhMDibLKIAc0eBqvBzW7Cv7IBiq9KPtoC8h xl5eCLerENcQ5Iq6Tyfnv9Ok8xUCgYEA0k//3/rPF3c92iCI/ScL6mIkey17GT6X hZGoZZa5EbRVMgR8GTh1B+P9TB+ZNwJDEB4PR70Sgd5U5+y/id858OEYLuMcuQuk 0ltzm22Cvaxnqoii4Enyy4wO17/NnN7btpTt6kWrDTD1jnx/BHI/a7kgtgVyb5xZ 6mWD2VjiukkCgYEAvMuzUqufhjMM6v5aF7QghM39dUUJAhK2TzCjYHYzBeu9MmgP HQ2B/gDETiojCZ0flPR6uQyYHmMrX+PXYwUOIfzvi0hbJF6ddYszBlTRQOhruoz8 OjoDe44tTOxtPzCL0zWmnlYkPpLuoEQPSgYnoVF/5BdAJlgqf35v+dBd8qUCgYAP AW48SOTlw7hCC/g6N8L94irALyqNTo35Fb9yICLsRHWfr/o6wnB3M6kq+UYxSpQG Xl6wu6jKY1ajhZzU9Xxo12amUcYG3fHQoH3LJTEi3142KLGWVzBfnYqhkinVe4Ep sc6X3Iir1EZw+CkH5C7qPLc8xX64v+sackvKAjGLIQKBgDBIsu7EcoZzL6hmjW/F JCVjaA6Smuor1XCMCHEa4aUl+1esv8ORvGwZq1bRsYDJD5U+K8+XxhiGzfg0IDW3 WkkpzNw1scQkU3nvHoC0JscUtYH3XBj3rIDrL8GB3jk+hevJCXv4Z04A/IRhjear dHm9qjNOto+ucP7rWSkpUsn9 '''.decode("base64")) def decode_ecpoint(ecpoint): return { "\x02": "compressed", "\x04": "uncompressed" }[ecpoint[0]], ecpoint[1:1+len(ecpoint)/2], ecpoint[1+len(ecpoint)/2:] def dumpasn1(der): from subprocess import call from tempfile import NamedTemporaryFile with NamedTemporaryFile() as f: f.write(der) f.flush() call(("dumpasn1", "-aop", f.name)) if __name__ == "__main__": show_manual_decode = False ec_rfc5915 = DER_Decode(der_test_keys["ec_rfc5915"], ECPrivateKey() )[0] ec_pkcs8 = DER_Decode(der_test_keys["ec_pkcs8"], PrivateKeyInfo())[0] ec_pkcs8_privateKey = DER_Decode(str(ec_pkcs8["privateKey"]), ECPrivateKey() )[0] rsa_rfc2313 = DER_Decode(der_test_keys["rsa_rfc2313"], RSAPrivateKey() )[0] rsa_pkcs8 = DER_Decode(der_test_keys["rsa_pkcs8"], PrivateKeyInfo())[0] rsa_pkcs8_privateKey = DER_Decode(str(rsa_pkcs8["privateKey"]), RSAPrivateKey() )[0] print print "EC RFC 5915" print ec_rfc5915.prettyPrint() if show_manual_decode: print compressed, Qx, Qy = decode_ecpoint(ec_rfc5915["publicKey"].asOctets()) print "version: ", ec_rfc5915["version"] print "privateKey:", str(ec_rfc5915["privateKey"]).encode("hex") print "parameters:", ec_rfc5915["parameters"] print "publicKey: ", compressed print " Qx: ", Qx.encode("hex") print " Qy: ", Qy.encode("hex") # This works, and lets .prettyPrint() display the ANY content properly, # but it breaks some of the key hackery we do after all this display stuff. #ec_pkcs8["privateKeyAlgorithm"]["parameters"] = DER_Decode(ec_pkcs8["privateKeyAlgorithm"]["parameters"])[0] print print "EC PKCS #8" print ec_pkcs8.prettyPrint() print ec_pkcs8_privateKey.prettyPrint() if show_manual_decode: print compressed, Qx, Qy = decode_ecpoint(ec_pkcs8_privateKey["publicKey"].asOctets()) print "version: ", ec_pkcs8["version"] print "privateKeyAlgorithm:", ec_pkcs8["privateKeyAlgorithm"][0] print " ", DER_Decode(ec_pkcs8["privateKeyAlgorithm"]["parameters"])[0] print "privateKey:" print " version: ", ec_pkcs8_privateKey["version"] print " privateKey:", str(ec_pkcs8_privateKey["privateKey"]).encode("hex") print " parameters:", ec_pkcs8_privateKey["parameters"] print " publicKey: ", compressed print " Qx: ", Qx.encode("hex") print " Qy: ", Qy.encode("hex") print print "RSA RFC 2313" print rsa_rfc2313.prettyPrint() if show_manual_decode: print print "version:", rsa_rfc2313["version"] print " n:", rsa_rfc2313["n"] print " e:", rsa_rfc2313["e"] print " d:", rsa_rfc2313["d"] print " p:", rsa_rfc2313["p"] print " q:", rsa_rfc2313["q"] print " dP:", rsa_rfc2313["dP"] print " dQ:", rsa_rfc2313["dQ"] print " u:", rsa_rfc2313["u"] #rsa_pkcs8["privateKeyAlgorithm"]["parameters"] = DER_Decode(rsa_pkcs8["privateKeyAlgorithm"]["parameters"])[0] print print "RSA PKCS #8" print rsa_pkcs8.prettyPrint() print rsa_pkcs8_privateKey.prettyPrint() if show_manual_decode: print print "version: ", rsa_pkcs8["version"] print "privateKeyAlgorithm:", rsa_pkcs8["privateKeyAlgorithm"][0] print "privateKey:" print " version:", rsa_pkcs8_privateKey["version"] print " n:", rsa_pkcs8_privateKey["n"] print " e:", rsa_pkcs8_privateKey["e"] print " d:", rsa_pkcs8_privateKey["d"] print " p:", rsa_pkcs8_privateKey["p"] print " q:", rsa_pkcs8_privateKey["q"] print " dP:", rsa_pkcs8_privateKey["dP"] print " dQ:", rsa_pkcs8_privateKey["dQ"] print " u:", rsa_pkcs8_privateKey["u"] # Generate PKCS #8 from ECPrivateKey and check against static data p8 = PrivateKeyInfo() ec = ECPrivateKey() ec["version"] = ec_rfc5915["version"] ec["privateKey"] = ec_rfc5915["privateKey"] ec["publicKey"] = ec_rfc5915["publicKey"] p8["version"] = 0 p8["privateKeyAlgorithm"] = AlgorithmIdentifier() p8["privateKeyAlgorithm"]["algorithm"] = "1.2.840.10045.2.1" p8["privateKeyAlgorithm"]["parameters"] = ObjectIdentifier(ec_rfc5915["parameters"]) p8["privateKey"] = DER_Encode(ec) der = DER_Encode(p8) #print; dumpasn1(der) #print; dumpasn1(der_test_keys["ec_pkcs8"]) print; print "Reencoded PKCS #8 {} static data".format("matches" if der == der_test_keys["ec_pkcs8"] else "doesn't match") # Try doing same thing with ecdsa package ASN.1 utilities. sk = SigningKey.from_der(der_test_keys["ec_rfc5915"]) vk = ECDSA_DER.encode_bitstring("\x00\x04" + sk.get_verifying_key().to_string()) ec = ECDSA_DER.encode_sequence(ECDSA_DER.encode_integer(1), ECDSA_DER.encode_octet_string(sk.to_string()), ECDSA_DER.encode_constructed(1, vk)) p8 = ECDSA_DER.encode_sequence(ECDSA_DER.encode_integer(0), ECDSA_DER.encode_sequence(encoded_oid_ecPublicKey, sk.curve.encoded_oid), ECDSA_DER.encode_octet_string(ec)) print; print "ECDSA-library PKCS #8 encoding {} pyasn1 PKCS #8 encoding".format("matches" if p8 == der_test_keys["ec_pkcs8"] else "doesn't match") # Generate ECPrivateKey from PKCS #8 and check against static data ec = ECPrivateKey() ec["version"] = ec_pkcs8_privateKey["version"] ec["privateKey"] = ec_pkcs8_privateKey["privateKey"] ec["parameters"] = str(DER_Decode(ec_pkcs8["privateKeyAlgorithm"]["parameters"])[0]) ec["publicKey"] = ec_pkcs8_privateKey["publicKey"] der = DER_Encode(ec) #print; dumpasn1(der) #print; dumpasn1(der_test_keys["ec_rfc5915"]) print; print "Reencoded PKCS #8 {} static data".format("matches" if der == der_test_keys["ec_rfc5915"] else "doesn't match") # Paranoia: Make sure we really can load the RFC 5915 we just generated. sk = SigningKey.from_der(der) print; print "ECDSA Python library parse of reencoded PKCS #8 data: {!r}".format(sk) # Same thing with ecdsa package ASN.1 utilities. car, cdr = ECDSA_DER.remove_sequence(der_test_keys["ec_pkcs8"]) assert cdr == "" version, cdr = ECDSA_DER.remove_integer(car) assert version == 0 car, ec = ECDSA_DER.remove_sequence(cdr) oid, cdr = ECDSA_DER.remove_object(car) assert oid == oid_ecPublicKey oid, cdr = ECDSA_DER.remove_object(cdr) curve = find_curve(oid) assert cdr == "" car, cdr = ECDSA_DER.remove_octet_string(ec) assert cdr == "" car, cdr = ECDSA_DER.remove_sequence(car) assert cdr == "" version, cdr = ECDSA_DER.remove_integer(car) assert version == 1 privkey, cdr = ECDSA_DER.remove_octet_string(cdr) tag, car, cdr = ECDSA_DER.remove_constructed(cdr) assert tag == 1 assert cdr == "" pubkey, cdr = ECDSA_DER.remove_bitstring(car) assert cdr == "" assert pubkey[:2] == "\x00\x04" sk = SigningKey.from_string(privkey, curve) print; print "ECDSA-library PKCS #8 decoding {} pyasn1 PKCS #8 decoding".format( "matches" if der == sk.to_der() else "doesn't match") 0' href='#n30'>30 31 32 33 34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  
           

                                    
  
                                                            

                                        
  




                                                                           
  


                                                                         
  


                                                                           
  










                                                                           

   
                   
 
                
                              

                             
                                 

      
                                                                                     




                                 


                                                                


                                      
                                                                           

                 
                                                                                            










                                                   
                                 












                                                                            
/*
 * csprng.c
 * --------
 * HAL interface to Cryptech CSPRNG.
 *
 * Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein
 * Copyright (c) 2014-2015, NORDUnet A/S
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the NORDUnet nor the names of its contributors may
 *   be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdint.h>

#include "hal.h"
#include "verilog_constants.h"

#ifndef WAIT_FOR_CSPRNG_VALID
#define WAIT_FOR_CSPRNG_VALID   1
#endif

hal_error_t hal_get_random(const hal_core_t *core, void *buffer, const size_t length)
{
  uint8_t temp[4], *buf = buffer;
  hal_error_t err;
  size_t i;

  if ((err = hal_core_check_name(&core, CSPRNG_NAME)) != HAL_OK)
    return err;

  for (i = 0; i < length; i += 4) {
    const int last = (length - i) < 4;

    if (WAIT_FOR_CSPRNG_VALID && (err = hal_io_wait_valid(core)) != HAL_OK)
      return err;

    if ((err = hal_io_read(core, CSPRNG_ADDR_RANDOM, (last ? temp : &buf[i]), 4)) != HAL_OK)
      return err;

    if (last)
      for (; i < length; i++)
        buf[i] = temp[i&3];
  }

  for (i = 0, buf = buffer; i < length; i++, buf++)
    if (*buf != 0)
      return HAL_OK;

  return HAL_ERROR_CSPRNG_BROKEN;
}

/*
 * "Any programmer who fails to comply with the standard naming, formatting,
 *  or commenting conventions should be shot.  If it so happens that it is
 *  inconvenient to shoot him, then he is to be politely requested to recode
 *  his program in adherence to the above standard."
 *                      -- Michael Spier, Digital Equipment Corporation
 *
 * Local variables:
 * indent-tabs-mode: nil
 * End:
 */