# 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
/*
 * test-rpc_get_version.c
 * ----------------------
 * Test code for RPC interface to Cryptech hash cores.
 *
 * Copyright (c) 2016, 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 <stdio.h>

#include <hal.h>

int main(int argc, char *argv[])
{
    uint32_t version;

#define check(op) { hal_error_t err; if ((err = (op)) != HAL_OK) { printf("%s: %s\n", #op, hal_error_string(err)); return 1; } }

    check(hal_rpc_client_init());
    check(hal_rpc_get_version(&version));
    printf("%08x\n", version);

    check(hal_rpc_client_close());
    return 0;
}
t_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")