Update cfssl to latest master.
This pulls in the pkcs11key change from https://github.com/cloudflare/cfssl/pull/330, and updates the Boulder code to match. Note: This change overwrites the local changes to our vendored CFSSL made in https://github.com/letsencrypt/boulder/pull/784. That's intentional: The upstream changes in https://github.com/cloudflare/cfssl/pull/330 accomplish the same thing, more cleanly.
This commit is contained in:
		
							parent
							
								
									e201632f60
								
							
						
					
					
						commit
						d05b9b833f
					
				|  | @ -12,51 +12,63 @@ | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/auth", | 			"ImportPath": "github.com/cloudflare/cfssl/auth", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/config", | 			"ImportPath": "github.com/cloudflare/cfssl/config", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs11key", | 			"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs11key", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs12", | 			"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs12", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs7", | 			"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs7", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/csr", | 			"ImportPath": "github.com/cloudflare/cfssl/csr", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/errors", | 			"ImportPath": "github.com/cloudflare/cfssl/errors", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/helpers", | 			"ImportPath": "github.com/cloudflare/cfssl/helpers", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/info", | 			"ImportPath": "github.com/cloudflare/cfssl/info", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/log", | 			"ImportPath": "github.com/cloudflare/cfssl/log", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/ocsp", | 			"ImportPath": "github.com/cloudflare/cfssl/ocsp", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/cloudflare/cfssl/signer", | 			"ImportPath": "github.com/cloudflare/cfssl/signer", | ||||||
| 			"Rev": "190c5f9713ef6c1460fb31ee785044b43bdb1b09" | 			"Comment": "1.1.0-56-gfed4546", | ||||||
|  | 			"Rev": "fed4546bc16a51b87ea8b18df7c26090c4c5b900" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/codegangsta/cli", | 			"ImportPath": "github.com/codegangsta/cli", | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/config.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										10
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/config.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | package pkcs11key | ||||||
|  | 
 | ||||||
|  | // Config contains configuration information required to use a PKCS
 | ||||||
|  | // #11 key.
 | ||||||
|  | type Config struct { | ||||||
|  | 	Module          string | ||||||
|  | 	TokenLabel      string | ||||||
|  | 	PIN             string | ||||||
|  | 	PrivateKeyLabel string | ||||||
|  | } | ||||||
							
								
								
									
										353
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										353
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/key.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,353 @@ | ||||||
|  | // +build !nopkcs11
 | ||||||
|  | 
 | ||||||
|  | // Package pkcs11key implements crypto.Signer for PKCS #11 private
 | ||||||
|  | // keys. Currently, only RSA keys are supported.
 | ||||||
|  | // See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-30/pkcs-11v2-30b-d6.pdf for
 | ||||||
|  | // details of the Cryptoki PKCS#11 API.
 | ||||||
|  | package pkcs11key | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"math/big" | ||||||
|  | 	"sync" | ||||||
|  | 
 | ||||||
|  | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/pkcs11" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // from src/pkg/crypto/rsa/pkcs1v15.go
 | ||||||
|  | var hashPrefixes = map[crypto.Hash][]byte{ | ||||||
|  | 	crypto.MD5:       {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, | ||||||
|  | 	crypto.SHA1:      {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, | ||||||
|  | 	crypto.SHA224:    {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, | ||||||
|  | 	crypto.SHA256:    {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, | ||||||
|  | 	crypto.SHA384:    {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, | ||||||
|  | 	crypto.SHA512:    {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, | ||||||
|  | 	crypto.MD5SHA1:   {}, // A special TLS case which doesn't use an ASN1 prefix.
 | ||||||
|  | 	crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14}, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Key is an implementation of the crypto.Signer interface using a key stored
 | ||||||
|  | // in a PKCS#11 hardware token.  This enables the use of PKCS#11 tokens with
 | ||||||
|  | // the Go x509 library's methods for signing certificates.
 | ||||||
|  | //
 | ||||||
|  | // Each Key represents one session. Its session handle is protected internally
 | ||||||
|  | // by a mutex, so at most one Sign operation can be active at a time. For best
 | ||||||
|  | // performance you may want to instantiate multiple Keys using pkcs11key.Pool.
 | ||||||
|  | // Each one will have its own session and can be used concurrently. Note that
 | ||||||
|  | // some smartcards like the Yubikey Neo do not support multiple simultaneous
 | ||||||
|  | // sessions and will error out on creation of the second Key object.
 | ||||||
|  | //
 | ||||||
|  | // Note: If you instantiate multiple Keys without using Pool, it is *highly*
 | ||||||
|  | // recommended that you create all your Key objects serially, on your main
 | ||||||
|  | // thread, checking for errors each time, and then farm them out for use by
 | ||||||
|  | // different goroutines. If you fail to do this, your application may attempt
 | ||||||
|  | // to login repeatedly with an incorrect PIN, locking the PKCS#11 token.
 | ||||||
|  | type Key struct { | ||||||
|  | 	// The PKCS#11 library to use
 | ||||||
|  | 	module *pkcs11.Ctx | ||||||
|  | 
 | ||||||
|  | 	// The path to the PKCS#11 library
 | ||||||
|  | 	modulePath string | ||||||
|  | 
 | ||||||
|  | 	// The label of the token to be used (mandatory).
 | ||||||
|  | 	// We will automatically search for this in the slot list.
 | ||||||
|  | 	tokenLabel string | ||||||
|  | 
 | ||||||
|  | 	// The PIN to be used to log in to the device
 | ||||||
|  | 	pin string | ||||||
|  | 
 | ||||||
|  | 	// The public key corresponding to the private key.
 | ||||||
|  | 	publicKey rsa.PublicKey | ||||||
|  | 
 | ||||||
|  | 	// The an ObjectHandle pointing to the private key on the HSM.
 | ||||||
|  | 	privateKeyHandle pkcs11.ObjectHandle | ||||||
|  | 
 | ||||||
|  | 	// A handle to the session used by this Key.
 | ||||||
|  | 	session   *pkcs11.SessionHandle | ||||||
|  | 	sessionMu sync.Mutex | ||||||
|  | 
 | ||||||
|  | 	// True if the private key has the CKA_ALWAYS_AUTHENTICATE attribute set.
 | ||||||
|  | 	alwaysAuthenticate bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var modules = make(map[string]*pkcs11.Ctx) | ||||||
|  | var modulesMu sync.Mutex | ||||||
|  | 
 | ||||||
|  | // initialize loads the given PKCS#11 module (shared library) if it is not
 | ||||||
|  | // already loaded. It's an error to load a PKCS#11 module multiple times, so we
 | ||||||
|  | // maintain a map of loaded modules. Note that there is no facility yet to
 | ||||||
|  | // unload a module ("finalize" in PKCS#11 parlance). In general, modules will
 | ||||||
|  | // be unloaded at the end of the process.  The only place where you are likely
 | ||||||
|  | // to need to explicitly unload a module is if you fork your process after a
 | ||||||
|  | // Key has already been created, and the child process also needs to use
 | ||||||
|  | // that module.
 | ||||||
|  | func initialize(modulePath string) (*pkcs11.Ctx, error) { | ||||||
|  | 	modulesMu.Lock() | ||||||
|  | 	defer modulesMu.Unlock() | ||||||
|  | 	module, ok := modules[modulePath] | ||||||
|  | 	if ok { | ||||||
|  | 		return module, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	module = pkcs11.New(modulePath) | ||||||
|  | 
 | ||||||
|  | 	if module == nil { | ||||||
|  | 		return nil, fmt.Errorf("unable to load PKCS#11 module") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err := module.Initialize() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	modules[modulePath] = module | ||||||
|  | 
 | ||||||
|  | 	return module, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // New instantiates a new handle to a PKCS #11-backed key.
 | ||||||
|  | func New(modulePath, tokenLabel, pin, privateKeyLabel string) (ps *Key, err error) { | ||||||
|  | 	module, err := initialize(modulePath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if module == nil { | ||||||
|  | 		err = fmt.Errorf("nil module") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Initialize a partial key
 | ||||||
|  | 	ps = &Key{ | ||||||
|  | 		module:     module, | ||||||
|  | 		modulePath: modulePath, | ||||||
|  | 		tokenLabel: tokenLabel, | ||||||
|  | 		pin:        pin, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Open a session
 | ||||||
|  | 	ps.sessionMu.Lock() | ||||||
|  | 	defer ps.sessionMu.Unlock() | ||||||
|  | 	session, err := ps.openSession() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ps.session = &session | ||||||
|  | 
 | ||||||
|  | 	// Fetch the private key by its label
 | ||||||
|  | 	privateKeyHandle, err := ps.getPrivateKey(module, session, privateKeyLabel) | ||||||
|  | 	if err != nil { | ||||||
|  | 		ps.module.CloseSession(session) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ps.privateKeyHandle = privateKeyHandle | ||||||
|  | 
 | ||||||
|  | 	publicKey, err := getPublicKey(module, session, privateKeyHandle) | ||||||
|  | 	if err != nil { | ||||||
|  | 		ps.module.CloseSession(session) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ps.publicKey = publicKey | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (ps *Key) getPrivateKey(module *pkcs11.Ctx, session pkcs11.SessionHandle, label string) (pkcs11.ObjectHandle, error) { | ||||||
|  | 	var noHandle pkcs11.ObjectHandle | ||||||
|  | 	template := []*pkcs11.Attribute{ | ||||||
|  | 		pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), | ||||||
|  | 		pkcs11.NewAttribute(pkcs11.CKA_LABEL, label), | ||||||
|  | 	} | ||||||
|  | 	if err := module.FindObjectsInit(session, template); err != nil { | ||||||
|  | 		return noHandle, err | ||||||
|  | 	} | ||||||
|  | 	objs, _, err := module.FindObjects(session, 2) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return noHandle, err | ||||||
|  | 	} | ||||||
|  | 	if err = module.FindObjectsFinal(session); err != nil { | ||||||
|  | 		return noHandle, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(objs) == 0 { | ||||||
|  | 		return noHandle, fmt.Errorf("private key not found") | ||||||
|  | 	} | ||||||
|  | 	privateKeyHandle := objs[0] | ||||||
|  | 
 | ||||||
|  | 	// Check whether the key has the CKA_ALWAYS_AUTHENTICATE attribute.
 | ||||||
|  | 	// If so, fail: we don't want to have to re-authenticate for each sign
 | ||||||
|  | 	// operation.
 | ||||||
|  | 	attributes, err := module.GetAttributeValue(session, privateKeyHandle, []*pkcs11.Attribute{ | ||||||
|  | 		pkcs11.NewAttribute(pkcs11.CKA_ALWAYS_AUTHENTICATE, false), | ||||||
|  | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return noHandle, err | ||||||
|  | 	} | ||||||
|  | 	for _, attribute := range attributes { | ||||||
|  | 		if len(attribute.Value) > 0 && attribute.Value[0] == 1 { | ||||||
|  | 			ps.alwaysAuthenticate = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return privateKeyHandle, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Get the public key matching a private key
 | ||||||
|  | // TODO: Add support for non-RSA keys, switching on CKA_KEY_TYPE
 | ||||||
|  | func getPublicKey(module *pkcs11.Ctx, session pkcs11.SessionHandle, privateKeyHandle pkcs11.ObjectHandle) (rsa.PublicKey, error) { | ||||||
|  | 	var noKey rsa.PublicKey | ||||||
|  | 	template := []*pkcs11.Attribute{ | ||||||
|  | 		pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), | ||||||
|  | 		pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), | ||||||
|  | 	} | ||||||
|  | 	attr, err := module.GetAttributeValue(session, privateKeyHandle, template) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return noKey, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	n := big.NewInt(0) | ||||||
|  | 	e := int(0) | ||||||
|  | 	gotModulus, gotExponent := false, false | ||||||
|  | 	for _, a := range attr { | ||||||
|  | 		if a.Type == pkcs11.CKA_MODULUS { | ||||||
|  | 			n.SetBytes(a.Value) | ||||||
|  | 			gotModulus = true | ||||||
|  | 		} else if a.Type == pkcs11.CKA_PUBLIC_EXPONENT { | ||||||
|  | 			bigE := big.NewInt(0) | ||||||
|  | 			bigE.SetBytes(a.Value) | ||||||
|  | 			e = int(bigE.Int64()) | ||||||
|  | 			gotExponent = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if !gotModulus || !gotExponent { | ||||||
|  | 		return noKey, errors.New("public key missing either modulus or exponent") | ||||||
|  | 	} | ||||||
|  | 	return rsa.PublicKey{ | ||||||
|  | 		N: n, | ||||||
|  | 		E: e, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Destroy tears down a Key by closing the session. It should be
 | ||||||
|  | // called before the key gets GC'ed, to avoid leaving dangling sessions.
 | ||||||
|  | func (ps *Key) Destroy() error { | ||||||
|  | 	if ps.session != nil { | ||||||
|  | 		// NOTE: We do not want to call module.Logout here. module.Logout applies
 | ||||||
|  | 		// application-wide. So if there are multiple sessions active, the other ones
 | ||||||
|  | 		// would be logged out as well, causing CKR_OBJECT_HANDLE_INVALID next
 | ||||||
|  | 		// time they try to sign something. It's also unnecessary to log out explicitly:
 | ||||||
|  | 		// module.CloseSession will log out once the last session in the application is
 | ||||||
|  | 		// closed.
 | ||||||
|  | 		ps.sessionMu.Lock() | ||||||
|  | 		defer ps.sessionMu.Unlock() | ||||||
|  | 		err := ps.module.CloseSession(*ps.session) | ||||||
|  | 		ps.session = nil | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (ps *Key) openSession() (pkcs11.SessionHandle, error) { | ||||||
|  | 	var noSession pkcs11.SessionHandle | ||||||
|  | 	slots, err := ps.module.GetSlotList(true) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return noSession, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, slot := range slots { | ||||||
|  | 		// Check that token label matches.
 | ||||||
|  | 		tokenInfo, err := ps.module.GetTokenInfo(slot) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return noSession, err | ||||||
|  | 		} | ||||||
|  | 		if tokenInfo.Label != ps.tokenLabel { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Open session
 | ||||||
|  | 		session, err := ps.module.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return session, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Login
 | ||||||
|  | 		// Note: Logged-in status is application-wide, not per session. But in
 | ||||||
|  | 		// practice it appears to be okay to login to a token multiple times with the same
 | ||||||
|  | 		// credentials.
 | ||||||
|  | 		if err = ps.module.Login(session, pkcs11.CKU_USER, ps.pin); err != nil { | ||||||
|  | 			ps.module.CloseSession(session) | ||||||
|  | 			return session, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return session, err | ||||||
|  | 	} | ||||||
|  | 	return noSession, fmt.Errorf("No slot found matching token label '%s'", ps.tokenLabel) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Public returns the public key for the PKCS #11 key.
 | ||||||
|  | func (ps *Key) Public() crypto.PublicKey { | ||||||
|  | 	return &ps.publicKey | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Sign performs a signature using the PKCS #11 key.
 | ||||||
|  | func (ps *Key) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { | ||||||
|  | 	ps.sessionMu.Lock() | ||||||
|  | 	defer ps.sessionMu.Unlock() | ||||||
|  | 	if ps.session == nil { | ||||||
|  | 		return nil, errors.New("Session was nil") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// When the alwaysAuthenticate bit is true (e.g. on a Yubikey NEO in PIV mode),
 | ||||||
|  | 	// each Sign has to include a Logout/Login, or the next Sign request will get
 | ||||||
|  | 	// CKR_USER_NOT_LOGGED_IN. This is very slow, but on the NEO it's not possible
 | ||||||
|  | 	// to clear the CKA_ALWAYS_AUTHENTICATE bit, so this is the only available
 | ||||||
|  | 	// workaround.
 | ||||||
|  | 	// Also, since logged in / logged out is application state rather than session
 | ||||||
|  | 	// state, we take a global lock while we do the logout and login, and during
 | ||||||
|  | 	// the signing.
 | ||||||
|  | 	if ps.alwaysAuthenticate { | ||||||
|  | 		modulesMu.Lock() | ||||||
|  | 		defer modulesMu.Unlock() | ||||||
|  | 		if err := ps.module.Logout(*ps.session); err != nil { | ||||||
|  | 			return nil, fmt.Errorf("logout: %s", err) | ||||||
|  | 		} | ||||||
|  | 		if err = ps.module.Login(*ps.session, pkcs11.CKU_USER, ps.pin); err != nil { | ||||||
|  | 			return nil, fmt.Errorf("login: %s", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Verify that the length of the hash is as expected
 | ||||||
|  | 	hash := opts.HashFunc() | ||||||
|  | 	hashLen := hash.Size() | ||||||
|  | 	if len(msg) != hashLen { | ||||||
|  | 		err = errors.New("input size does not match hash function output size") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Add DigestInfo prefix
 | ||||||
|  | 	// TODO: Switch mechanisms based on CKA_KEY_TYPE
 | ||||||
|  | 	mechanism := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS, nil)} | ||||||
|  | 	prefix, ok := hashPrefixes[hash] | ||||||
|  | 	if !ok { | ||||||
|  | 		err = errors.New("unknown hash function") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	signatureInput := append(prefix, msg...) | ||||||
|  | 
 | ||||||
|  | 	// Perform the sign operation
 | ||||||
|  | 	err = ps.module.SignInit(*ps.session, mechanism, ps.privateKeyHandle) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("sign init: %s", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	signature, err = ps.module.Sign(*ps.session, signatureInput) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("sign: %s", err) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										247
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/pkcs11key.go
								
								
									generated
								
								
									vendored
								
								
							
							
						
						
									
										247
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/pkcs11key.go
								
								
									generated
								
								
									vendored
								
								
							|  | @ -1,247 +0,0 @@ | ||||||
| // +build !nopkcs11
 |  | ||||||
| 
 |  | ||||||
| // Package pkcs11key implements crypto.Signer for PKCS #11 private
 |  | ||||||
| // keys. Currently, only RSA keys are support.
 |  | ||||||
| package pkcs11key |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"crypto" |  | ||||||
| 	"crypto/rsa" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"math/big" |  | ||||||
| 
 |  | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/pkcs11" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // from src/pkg/crypto/rsa/pkcs1v15.go
 |  | ||||||
| var hashPrefixes = map[crypto.Hash][]byte{ |  | ||||||
| 	crypto.MD5:       {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, |  | ||||||
| 	crypto.SHA1:      {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, |  | ||||||
| 	crypto.SHA224:    {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, |  | ||||||
| 	crypto.SHA256:    {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, |  | ||||||
| 	crypto.SHA384:    {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, |  | ||||||
| 	crypto.SHA512:    {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, |  | ||||||
| 	crypto.MD5SHA1:   {}, // A special TLS case which doesn't use an ASN1 prefix.
 |  | ||||||
| 	crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14}, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // PKCS11Key is an implementation of the crypto.Signer interface
 |  | ||||||
| // using a key stored in a PKCS#11 hardware token.  This enables
 |  | ||||||
| // the use of PKCS#11 tokens with the Go x509 library's methods
 |  | ||||||
| // for signing certificates.
 |  | ||||||
| type PKCS11Key struct { |  | ||||||
| 	// The PKCS#11 library to use
 |  | ||||||
| 	module *pkcs11.Ctx |  | ||||||
| 
 |  | ||||||
| 	// The slot id of the token to be used. Both this and tokenLabel must match to
 |  | ||||||
| 	// be used.
 |  | ||||||
| 	slotID int |  | ||||||
| 
 |  | ||||||
| 	// The label of the token to be used.
 |  | ||||||
| 	// We will automatically search for this in the slot list.
 |  | ||||||
| 	tokenLabel string |  | ||||||
| 
 |  | ||||||
| 	// The PIN to be used to log in to the device
 |  | ||||||
| 	pin string |  | ||||||
| 
 |  | ||||||
| 	// The public key corresponding to the private key.
 |  | ||||||
| 	publicKey rsa.PublicKey |  | ||||||
| 
 |  | ||||||
| 	// The an ObjectHandle pointing to the private key on the HSM.
 |  | ||||||
| 	privateKeyHandle pkcs11.ObjectHandle |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // New instantiates a new handle to a PKCS #11-backed key.
 |  | ||||||
| func New(module, tokenLabel, pin, privLabel string, slotID int) (ps *PKCS11Key, err error) { |  | ||||||
| 	// Set up a new pkcs11 object and initialize it
 |  | ||||||
| 	p := pkcs11.New(module) |  | ||||||
| 	if p == nil { |  | ||||||
| 		err = errors.New("unable to load PKCS#11 module") |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if err = p.Initialize(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Initialize a partial key
 |  | ||||||
| 	ps = &PKCS11Key{ |  | ||||||
| 		module:     p, |  | ||||||
| 		slotID:     slotID, |  | ||||||
| 		tokenLabel: tokenLabel, |  | ||||||
| 		pin:        pin, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Look up the private key
 |  | ||||||
| 	session, err := ps.openSession() |  | ||||||
| 	if err != nil { |  | ||||||
| 		ps.Destroy() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	defer ps.closeSession(session) |  | ||||||
| 
 |  | ||||||
| 	template := []*pkcs11.Attribute{ |  | ||||||
| 		pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), |  | ||||||
| 		pkcs11.NewAttribute(pkcs11.CKA_LABEL, privLabel), |  | ||||||
| 	} |  | ||||||
| 	if err = p.FindObjectsInit(session, template); err != nil { |  | ||||||
| 		ps.Destroy() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	objs, _, err := p.FindObjects(session, 2) |  | ||||||
| 	if err != nil { |  | ||||||
| 		ps.Destroy() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if err = p.FindObjectsFinal(session); err != nil { |  | ||||||
| 		ps.Destroy() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if len(objs) == 0 { |  | ||||||
| 		err = errors.New("private key not found") |  | ||||||
| 		ps.Destroy() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	ps.privateKeyHandle = objs[0] |  | ||||||
| 
 |  | ||||||
| 	// Populate the pubic key from the private key
 |  | ||||||
| 	// TODO: Add support for non-RSA keys, switching on CKA_KEY_TYPE
 |  | ||||||
| 	template = []*pkcs11.Attribute{ |  | ||||||
| 		pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), |  | ||||||
| 		pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), |  | ||||||
| 	} |  | ||||||
| 	attr, err := p.GetAttributeValue(session, ps.privateKeyHandle, template) |  | ||||||
| 	if err != nil { |  | ||||||
| 		ps.Destroy() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	n := big.NewInt(0) |  | ||||||
| 	e := int(0) |  | ||||||
| 	gotModulus, gotExponent := false, false |  | ||||||
| 	for _, a := range attr { |  | ||||||
| 		if a.Type == pkcs11.CKA_MODULUS { |  | ||||||
| 			n.SetBytes(a.Value) |  | ||||||
| 			gotModulus = true |  | ||||||
| 		} else if a.Type == pkcs11.CKA_PUBLIC_EXPONENT { |  | ||||||
| 			bigE := big.NewInt(0) |  | ||||||
| 			bigE.SetBytes(a.Value) |  | ||||||
| 			e = int(bigE.Int64()) |  | ||||||
| 			gotExponent = true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if !gotModulus || !gotExponent { |  | ||||||
| 		ps.Destroy() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	ps.publicKey = rsa.PublicKey{ |  | ||||||
| 		N: n, |  | ||||||
| 		E: e, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Destroy tears down a PKCS11Key.
 |  | ||||||
| //
 |  | ||||||
| // This method must be called before the PKCS11Key is GC'ed, in order
 |  | ||||||
| // to ensure that the PKCS#11 module itself is properly finalized and
 |  | ||||||
| // destroyed.
 |  | ||||||
| //
 |  | ||||||
| // The idiomatic way to do this (assuming no need for a long-lived
 |  | ||||||
| // signer) is as follows:
 |  | ||||||
| //
 |  | ||||||
| //   ps, err := NewPKCS11Signer(...)
 |  | ||||||
| //   if err != nil { ... }
 |  | ||||||
| //   defer ps.Destroy()
 |  | ||||||
| func (ps *PKCS11Key) Destroy() { |  | ||||||
| 	if ps.module != nil { |  | ||||||
| 		ps.module.Finalize() |  | ||||||
| 		ps.module.Destroy() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (ps *PKCS11Key) openSession() (session pkcs11.SessionHandle, err error) { |  | ||||||
| 	// Check if there is a PCKS11 token with slots. It has side-effects that
 |  | ||||||
| 	// allow the rest of the code here to work.
 |  | ||||||
| 	_, err = ps.module.GetSlotList(true) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	slotID := uint(ps.slotID) |  | ||||||
| 	// Look up slot by id
 |  | ||||||
| 	tokenInfo, err := ps.module.GetTokenInfo(slotID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Check that token label matches.
 |  | ||||||
| 	if tokenInfo.Label != ps.tokenLabel { |  | ||||||
| 		err = fmt.Errorf("Token label in slot %d was '%s', expected '%s'", |  | ||||||
| 			slotID, tokenInfo.Label, ps.tokenLabel) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	// Open session
 |  | ||||||
| 	session, err = ps.module.OpenSession(slotID, pkcs11.CKF_SERIAL_SESSION) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return session, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Login
 |  | ||||||
| 	if err = ps.module.Login(session, pkcs11.CKU_USER, ps.pin); err != nil { |  | ||||||
| 		return session, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return session, err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (ps *PKCS11Key) closeSession(session pkcs11.SessionHandle) { |  | ||||||
| 	ps.module.Logout(session) |  | ||||||
| 	ps.module.CloseSession(session) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Public returns the public key for the PKCS #11 key.
 |  | ||||||
| func (ps *PKCS11Key) Public() crypto.PublicKey { |  | ||||||
| 	return &ps.publicKey |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Sign performs a signature using the PKCS #11 key.
 |  | ||||||
| func (ps *PKCS11Key) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { |  | ||||||
| 	// Verify that the length of the hash is as expected
 |  | ||||||
| 	hash := opts.HashFunc() |  | ||||||
| 	hashLen := hash.Size() |  | ||||||
| 	if len(msg) != hashLen { |  | ||||||
| 		err = errors.New("input size does not match hash function output size") |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Add DigestInfo prefix
 |  | ||||||
| 	// TODO: Switch mechanisms based on CKA_KEY_TYPE
 |  | ||||||
| 	mechanism := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS, nil)} |  | ||||||
| 	prefix, ok := hashPrefixes[hash] |  | ||||||
| 	if !ok { |  | ||||||
| 		err = errors.New("unknown hash function") |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	signatureInput := append(prefix, msg...) |  | ||||||
| 
 |  | ||||||
| 	// Open a session
 |  | ||||||
| 	session, err := ps.openSession() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	defer ps.closeSession(session) |  | ||||||
| 
 |  | ||||||
| 	// Perform the sign operation
 |  | ||||||
| 	err = ps.module.SignInit(session, mechanism, ps.privateKeyHandle) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	signature, err = ps.module.Sign(session, signatureInput) |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
							
								
								
									
										88
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/pkcs11key_bench_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										88
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/pkcs11key_bench_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,88 @@ | ||||||
|  | package pkcs11key | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"crypto/x509" | ||||||
|  | 	"flag" | ||||||
|  | 	"math/big" | ||||||
|  | 	"runtime" | ||||||
|  | 	"testing" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var module = flag.String("module", "", "Path to PKCS11 module") | ||||||
|  | var tokenLabel = flag.String("tokenLabel", "", "Token label") | ||||||
|  | var pin = flag.String("pin", "", "PIN") | ||||||
|  | var privateKeyLabel = flag.String("privateKeyLabel", "", "Private key label") | ||||||
|  | var sessionCount = flag.Int("sessions", runtime.GOMAXPROCS(-1), `Number of PKCS#11 sessions to use. | ||||||
|  | For SoftHSM, GOMAXPROCS is appropriate, but for an external HSM the optimum session count depends on the HSM's parallelism.`) | ||||||
|  | 
 | ||||||
|  | // BenchmarkPKCS11 signs a certificate repeatedly using a PKCS11 token and
 | ||||||
|  | // measures speed. To run (with SoftHSM):
 | ||||||
|  | // go test -bench=. -benchtime 5s ./crypto/pkcs11key/ \
 | ||||||
|  | //   -module /usr/lib/softhsm/libsofthsm.so -token-label "softhsm token" \
 | ||||||
|  | //   -pin 1234 -private-key-label "my key" -cpu 4
 | ||||||
|  | // You can adjust benchtime if you want to run for longer or shorter, and change
 | ||||||
|  | // the number of CPUs to select the parallelism you want.
 | ||||||
|  | func BenchmarkPKCS11(b *testing.B) { | ||||||
|  | 	if *module == "" || *tokenLabel == "" || *pin == "" || *privateKeyLabel == "" { | ||||||
|  | 		b.Fatal("Must pass all flags: module, tokenLabel, pin, and privateKeyLabel") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// A minimal, bogus certificate to be signed.
 | ||||||
|  | 	// Note: we choose a large N to make up for some of the missing fields in the
 | ||||||
|  | 	// bogus certificate, so we wind up something approximately the size of a real
 | ||||||
|  | 	// certificate.
 | ||||||
|  | 	N := big.NewInt(1) | ||||||
|  | 	N.Lsh(N, 6000) | ||||||
|  | 	template := x509.Certificate{ | ||||||
|  | 		SerialNumber:       big.NewInt(1), | ||||||
|  | 		PublicKeyAlgorithm: x509.RSA, | ||||||
|  | 		NotBefore:          time.Now(), | ||||||
|  | 		NotAfter:           time.Now(), | ||||||
|  | 
 | ||||||
|  | 		PublicKey: &rsa.PublicKey{ | ||||||
|  | 			N: N, | ||||||
|  | 			E: 1 << 17, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pool, err := NewPool(*sessionCount, *module, *tokenLabel, *pin, *privateKeyLabel) | ||||||
|  | 	if err != nil { | ||||||
|  | 		b.Fatal(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	defer pool.Destroy() | ||||||
|  | 
 | ||||||
|  | 	instance := pool.get() | ||||||
|  | 	if instance.alwaysAuthenticate { | ||||||
|  | 		b.Log("WARNING: Token has CKA_ALWAYS_AUTHENTICATE attribute, which makes signing slow.") | ||||||
|  | 	} | ||||||
|  | 	pool.put(instance) | ||||||
|  | 
 | ||||||
|  | 	// Reset the benchmarking timer so we don't include setup time.
 | ||||||
|  | 	b.ResetTimer() | ||||||
|  | 
 | ||||||
|  | 	// Start recording total time. Go's benchmarking code is interested in
 | ||||||
|  | 	// nanoseconds per op, but we're also interested in the total throughput.
 | ||||||
|  | 	start := time.Now() | ||||||
|  | 
 | ||||||
|  | 	b.RunParallel(func(pb *testing.PB) { | ||||||
|  | 		for pb.Next() { | ||||||
|  | 			_, err = x509.CreateCertificate(rand.Reader, &template, &template, template.PublicKey, pool) | ||||||
|  | 			if err != nil { | ||||||
|  | 				b.Fatal(err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	elapsedTime := time.Now().Sub(start) | ||||||
|  | 	b.Logf("Time, count, ops / second: %s, %d, %g", elapsedTime, b.N, float64(b.N)*float64(time.Second)/float64(elapsedTime)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Dummy test to avoid getting "warning: no tests found"
 | ||||||
|  | func TestNothing(t *testing.T) { | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/pool.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										100
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/pool.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,100 @@ | ||||||
|  | package pkcs11key | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Pool is a pool of Keys suitable for high performance parallel work. Key
 | ||||||
|  | // on its own is suitable for multi-threaded use because it has built-in
 | ||||||
|  | // locking, but one Key can have at most one operation inflight at a time.
 | ||||||
|  | // If you are using an HSM that supports multiple sessions, you may want to
 | ||||||
|  | // use a Pool instead, which contains multiple signers. Pool satisfies the
 | ||||||
|  | // Signer interface just as Key does, and farms out work to multiple sessions
 | ||||||
|  | // under the hood. This assumes you are calling Sign from multiple goroutines
 | ||||||
|  | // (as would be common in an RPC or HTTP environment). If you only call Sign
 | ||||||
|  | // from a single goroutine, you will only ever get single-session performance.
 | ||||||
|  | type Pool struct { | ||||||
|  | 	// This slice acts more or less like a concurrent stack. Keys are popped off
 | ||||||
|  | 	// the top for use, and then pushed back on when they are no longer in use.
 | ||||||
|  | 	signers []*Key | ||||||
|  | 	// The initial length of signers, before any are popped off for use.
 | ||||||
|  | 	totalCount int | ||||||
|  | 	// This variable signals the condition that there are Keys available to be
 | ||||||
|  | 	// used.
 | ||||||
|  | 	cond *sync.Cond | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *Pool) get() *Key { | ||||||
|  | 	p.cond.L.Lock() | ||||||
|  | 	for len(p.signers) == 0 { | ||||||
|  | 		p.cond.Wait() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	instance := p.signers[len(p.signers)-1] | ||||||
|  | 	p.signers = p.signers[:len(p.signers)-1] | ||||||
|  | 	p.cond.L.Unlock() | ||||||
|  | 	return instance | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *Pool) put(instance *Key) { | ||||||
|  | 	p.cond.L.Lock() | ||||||
|  | 	p.signers = append(p.signers, instance) | ||||||
|  | 	p.cond.Signal() | ||||||
|  | 	p.cond.L.Unlock() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Sign performs a signature using an available PKCS #11 key. If there is no key
 | ||||||
|  | // available, it blocks until there is.
 | ||||||
|  | func (p *Pool) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { | ||||||
|  | 	instance := p.get() | ||||||
|  | 	defer p.put(instance) | ||||||
|  | 	return instance.Sign(rand, msg, opts) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Public returns the public key of any one of the signers in the pool. Since
 | ||||||
|  | // they were all created with the same arguments, the public key should be the
 | ||||||
|  | // same for each one.
 | ||||||
|  | func (p *Pool) Public() crypto.PublicKey { | ||||||
|  | 	instance := p.get() | ||||||
|  | 	defer p.put(instance) | ||||||
|  | 	return instance.Public() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPool creates a pool of Keys of size n.
 | ||||||
|  | func NewPool(n int, modulePath, tokenLabel, pin, privateKeyLabel string) (*Pool, error) { | ||||||
|  | 	var err error | ||||||
|  | 	signers := make([]*Key, n) | ||||||
|  | 	for i := 0; i < n; i++ { | ||||||
|  | 		signers[i], err = New(modulePath, tokenLabel, pin, privateKeyLabel) | ||||||
|  | 		// If any of the signers fail, exit early. This could be, e.g., a bad PIN,
 | ||||||
|  | 		// and we want to make sure not to lock the token.
 | ||||||
|  | 		if err != nil { | ||||||
|  | 			for j := 0; j < i; j++ { | ||||||
|  | 				signers[j].Destroy() | ||||||
|  | 			} | ||||||
|  | 			return nil, fmt.Errorf("pkcs11key: problem making Key: %s", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var mutex sync.Mutex | ||||||
|  | 	return &Pool{ | ||||||
|  | 		signers:    signers, | ||||||
|  | 		totalCount: len(signers), | ||||||
|  | 		cond:       sync.NewCond(&mutex), | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Destroy calls destroy for each of the member keys, shutting down their
 | ||||||
|  | // sessions.
 | ||||||
|  | func (p *Pool) Destroy() error { | ||||||
|  | 	for i := 0; i < p.totalCount; i++ { | ||||||
|  | 		err := p.get().Destroy() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("destroy error: %s", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| package csr | package csr | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"crypto" | ||||||
| 	"crypto/ecdsa" | 	"crypto/ecdsa" | ||||||
| 	"crypto/elliptic" | 	"crypto/elliptic" | ||||||
| 	"crypto/rand" | 	"crypto/rand" | ||||||
|  | @ -14,6 +15,7 @@ import ( | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | 	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | ||||||
|  | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers" | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -32,33 +34,51 @@ type Name struct { | ||||||
| 	OU string // OrganisationalUnitName
 | 	OU string // OrganisationalUnitName
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // A KeyRequest contains the algorithm and key size for a new private
 | // A KeyRequest is a generic request for a new key.
 | ||||||
| // key.
 | type KeyRequest interface { | ||||||
| type KeyRequest struct { | 	Algo() string | ||||||
| 	Algo string `json:"algo"` | 	Size() int | ||||||
| 	Size int    `json:"size"` | 	Generate() (crypto.PrivateKey, error) | ||||||
|  | 	SigAlgo() x509.SignatureAlgorithm | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // The DefaultKeyRequest is used when no key request data is provided
 | // A BasicKeyRequest contains the algorithm and key size for a new private key.
 | ||||||
| // in the request. This should be a safe default.
 | type BasicKeyRequest struct { | ||||||
| var DefaultKeyRequest = KeyRequest{ | 	A string `json:"algo"` | ||||||
| 	Algo: "ecdsa", | 	S int    `json:"size"` | ||||||
| 	Size: curveP256, | } | ||||||
|  | 
 | ||||||
|  | // NewBasicKeyRequest returns a default BasicKeyRequest.
 | ||||||
|  | func NewBasicKeyRequest() *BasicKeyRequest { | ||||||
|  | 	return &BasicKeyRequest{"ecdsa", curveP256} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Algo returns the requested key algorithm represented as a string.
 | ||||||
|  | func (kr *BasicKeyRequest) Algo() string { | ||||||
|  | 	return kr.A | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Size returns the requested key size.
 | ||||||
|  | func (kr *BasicKeyRequest) Size() int { | ||||||
|  | 	return kr.S | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Generate generates a key as specified in the request. Currently,
 | // Generate generates a key as specified in the request. Currently,
 | ||||||
| // only ECDSA and RSA are supported.
 | // only ECDSA and RSA are supported.
 | ||||||
| func (kr *KeyRequest) Generate() (interface{}, error) { | func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) { | ||||||
| 	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo, kr.Size) | 	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size()) | ||||||
| 	switch kr.Algo { | 	switch kr.Algo() { | ||||||
| 	case "rsa": | 	case "rsa": | ||||||
| 		if kr.Size < 2048 { | 		if kr.Size() < 2048 { | ||||||
| 			return nil, errors.New("RSA key is too weak") | 			return nil, errors.New("RSA key is too weak") | ||||||
| 		} | 		} | ||||||
| 		return rsa.GenerateKey(rand.Reader, kr.Size) | 		if kr.Size() > 8192 { | ||||||
|  | 			return nil, errors.New("RSA key size too large") | ||||||
|  | 		} | ||||||
|  | 		return rsa.GenerateKey(rand.Reader, kr.Size()) | ||||||
| 	case "ecdsa": | 	case "ecdsa": | ||||||
| 		var curve elliptic.Curve | 		var curve elliptic.Curve | ||||||
| 		switch kr.Size { | 		switch kr.Size() { | ||||||
| 		case curveP256: | 		case curveP256: | ||||||
| 			curve = elliptic.P256() | 			curve = elliptic.P256() | ||||||
| 		case curveP384: | 		case curveP384: | ||||||
|  | @ -76,26 +96,26 @@ func (kr *KeyRequest) Generate() (interface{}, error) { | ||||||
| 
 | 
 | ||||||
| // SigAlgo returns an appropriate X.509 signature algorithm given the
 | // SigAlgo returns an appropriate X.509 signature algorithm given the
 | ||||||
| // key request's type and size.
 | // key request's type and size.
 | ||||||
| func (kr *KeyRequest) SigAlgo() x509.SignatureAlgorithm { | func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm { | ||||||
| 	switch kr.Algo { | 	switch kr.Algo() { | ||||||
| 	case "rsa": | 	case "rsa": | ||||||
| 		switch { | 		switch { | ||||||
| 		case kr.Size >= 4096: | 		case kr.Size() >= 4096: | ||||||
| 			return x509.SHA512WithRSA | 			return x509.SHA512WithRSA | ||||||
| 		case kr.Size >= 3072: | 		case kr.Size() >= 3072: | ||||||
| 			return x509.SHA384WithRSA | 			return x509.SHA384WithRSA | ||||||
| 		case kr.Size >= 2048: | 		case kr.Size() >= 2048: | ||||||
| 			return x509.SHA256WithRSA | 			return x509.SHA256WithRSA | ||||||
| 		default: | 		default: | ||||||
| 			return x509.SHA1WithRSA | 			return x509.SHA1WithRSA | ||||||
| 		} | 		} | ||||||
| 	case "ecdsa": | 	case "ecdsa": | ||||||
| 		switch { | 		switch kr.Size() { | ||||||
| 		case kr.Size == curveP521: | 		case curveP521: | ||||||
| 			return x509.ECDSAWithSHA512 | 			return x509.ECDSAWithSHA512 | ||||||
| 		case kr.Size == curveP384: | 		case curveP384: | ||||||
| 			return x509.ECDSAWithSHA384 | 			return x509.ECDSAWithSHA384 | ||||||
| 		case kr.Size == curveP256: | 		case curveP256: | ||||||
| 			return x509.ECDSAWithSHA256 | 			return x509.ECDSAWithSHA256 | ||||||
| 		default: | 		default: | ||||||
| 			return x509.ECDSAWithSHA1 | 			return x509.ECDSAWithSHA1 | ||||||
|  | @ -117,10 +137,18 @@ type CertificateRequest struct { | ||||||
| 	CN         string | 	CN         string | ||||||
| 	Names      []Name     `json:"names"` | 	Names      []Name     `json:"names"` | ||||||
| 	Hosts      []string   `json:"hosts"` | 	Hosts      []string   `json:"hosts"` | ||||||
| 	KeyRequest *KeyRequest `json:"key,omitempty"` | 	KeyRequest KeyRequest `json:"key,omitempty"` | ||||||
| 	CA         *CAConfig  `json:"ca,omitempty"` | 	CA         *CAConfig  `json:"ca,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // New returns a new, empty CertificateRequest with a
 | ||||||
|  | // BasicKeyRequest.
 | ||||||
|  | func New() *CertificateRequest { | ||||||
|  | 	return &CertificateRequest{ | ||||||
|  | 		KeyRequest: &BasicKeyRequest{}, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // appendIf appends to a if s is not an empty string.
 | // appendIf appends to a if s is not an empty string.
 | ||||||
| func appendIf(s string, a *[]string) { | func appendIf(s string, a *[]string) { | ||||||
| 	if s != "" { | 	if s != "" { | ||||||
|  | @ -152,13 +180,10 @@ func (cr *CertificateRequest) Name() pkix.Name { | ||||||
| func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) { | func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) { | ||||||
| 	log.Info("received CSR") | 	log.Info("received CSR") | ||||||
| 	if req.KeyRequest == nil { | 	if req.KeyRequest == nil { | ||||||
| 		req.KeyRequest = &KeyRequest{ | 		req.KeyRequest = NewBasicKeyRequest() | ||||||
| 			Algo: DefaultKeyRequest.Algo, |  | ||||||
| 			Size: DefaultKeyRequest.Size, |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	log.Infof("generating key: %s-%d", req.KeyRequest.Algo, req.KeyRequest.Size) | 	log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size()) | ||||||
| 	priv, err := req.KeyRequest.Generate() | 	priv, err := req.KeyRequest.Generate() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err) | 		err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err) | ||||||
|  | @ -249,3 +274,53 @@ func IsNameEmpty(n Name) bool { | ||||||
| 	} | 	} | ||||||
| 	return false | 	return false | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // Regenerate uses the provided CSR as a template for signing a new
 | ||||||
|  | // CSR using priv.
 | ||||||
|  | func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) { | ||||||
|  | 	req, extra, err := helpers.ParseCSR(csr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} else if len(extra) > 0 { | ||||||
|  | 		return nil, errors.New("csr: trailing data in certificate request") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return x509.CreateCertificateRequest(rand.Reader, req, priv) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Generate creates a new CSR from a CertificateRequest structure and
 | ||||||
|  | // an existing key. The KeyRequest field is ignored.
 | ||||||
|  | func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) { | ||||||
|  | 	sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256) | ||||||
|  | 	if sigAlgo == x509.UnknownSignatureAlgorithm { | ||||||
|  | 		return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var tpl = x509.CertificateRequest{ | ||||||
|  | 		Subject:            req.Name(), | ||||||
|  | 		SignatureAlgorithm: sigAlgo, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for i := range req.Hosts { | ||||||
|  | 		if ip := net.ParseIP(req.Hosts[i]); ip != nil { | ||||||
|  | 			tpl.IPAddresses = append(tpl.IPAddresses, ip) | ||||||
|  | 		} else { | ||||||
|  | 			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Errorf("failed to generate a CSR: %v", err) | ||||||
|  | 		err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	block := pem.Block{ | ||||||
|  | 		Type:  "CERTIFICATE REQUEST", | ||||||
|  | 		Bytes: csr, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Info("encoded CSR") | ||||||
|  | 	csr = pem.EncodeToMemory(&block) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package csr | package csr | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"crypto" | ||||||
| 	"crypto/ecdsa" | 	"crypto/ecdsa" | ||||||
| 	"crypto/elliptic" | 	"crypto/elliptic" | ||||||
| 	"crypto/rsa" | 	"crypto/rsa" | ||||||
|  | @ -9,13 +10,13 @@ import ( | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | ||||||
|  | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // TestKeyRequest ensures that key generation returns the same type of
 | // TestBasicKeyRequest ensures that key generation returns the same type of
 | ||||||
| // key specified in the KeyRequest.
 | // key specified in the BasicKeyRequest.
 | ||||||
| func TestKeyRequest(t *testing.T) { | func TestBasicKeyRequest(t *testing.T) { | ||||||
| 	var kr = &KeyRequest{"ecdsa", 256} | 	kr := NewBasicKeyRequest() | ||||||
| 
 |  | ||||||
| 	priv, err := kr.Generate() | 	priv, err := kr.Generate() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("%v", err) | 		t.Fatalf("%v", err) | ||||||
|  | @ -23,11 +24,11 @@ func TestKeyRequest(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| 	switch priv.(type) { | 	switch priv.(type) { | ||||||
| 	case *rsa.PrivateKey: | 	case *rsa.PrivateKey: | ||||||
| 		if kr.Algo != "rsa" { | 		if kr.Algo() != "rsa" { | ||||||
| 			t.Fatal("RSA key generated, but expected", kr.Algo) | 			t.Fatal("RSA key generated, but expected", kr.Algo) | ||||||
| 		} | 		} | ||||||
| 	case *ecdsa.PrivateKey: | 	case *ecdsa.PrivateKey: | ||||||
| 		if kr.Algo != "ecdsa" { | 		if kr.Algo() != "ecdsa" { | ||||||
| 			t.Fatal("ECDSA key generated, but expected", kr.Algo) | 			t.Fatal("ECDSA key generated, but expected", kr.Algo) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -36,7 +37,6 @@ func TestKeyRequest(t *testing.T) { | ||||||
| // TestPKIXName validates building a pkix.Name structure from a
 | // TestPKIXName validates building a pkix.Name structure from a
 | ||||||
| // CertificateRequest.
 | // CertificateRequest.
 | ||||||
| func TestPKIXName(t *testing.T) { | func TestPKIXName(t *testing.T) { | ||||||
| 	var kr = KeyRequest{"ecdsa", 256} |  | ||||||
| 	var cr = &CertificateRequest{ | 	var cr = &CertificateRequest{ | ||||||
| 		CN: "Test Common Name", | 		CN: "Test Common Name", | ||||||
| 		Names: []Name{ | 		Names: []Name{ | ||||||
|  | @ -56,7 +56,7 @@ func TestPKIXName(t *testing.T) { | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | ||||||
| 		KeyRequest: &kr, | 		KeyRequest: NewBasicKeyRequest(), | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	name := cr.Name() | 	name := cr.Name() | ||||||
|  | @ -78,7 +78,6 @@ func TestPKIXName(t *testing.T) { | ||||||
| // TestParseRequest ensures that a valid certificate request does not
 | // TestParseRequest ensures that a valid certificate request does not
 | ||||||
| // error.
 | // error.
 | ||||||
| func TestParseRequest(t *testing.T) { | func TestParseRequest(t *testing.T) { | ||||||
| 	var kr = KeyRequest{"ecdsa", 256} |  | ||||||
| 	var cr = &CertificateRequest{ | 	var cr = &CertificateRequest{ | ||||||
| 		CN: "Test Common Name", | 		CN: "Test Common Name", | ||||||
| 		Names: []Name{ | 		Names: []Name{ | ||||||
|  | @ -98,7 +97,7 @@ func TestParseRequest(t *testing.T) { | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, | ||||||
| 		KeyRequest: &kr, | 		KeyRequest: NewBasicKeyRequest(), | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, _, err := ParseRequest(cr) | 	_, _, err := ParseRequest(cr) | ||||||
|  | @ -126,7 +125,7 @@ func TestECGeneration(t *testing.T) { | ||||||
| 	var eckey *ecdsa.PrivateKey | 	var eckey *ecdsa.PrivateKey | ||||||
| 
 | 
 | ||||||
| 	for _, sz := range []int{256, 384, 521} { | 	for _, sz := range []int{256, 384, 521} { | ||||||
| 		kr := &KeyRequest{Algo: "ecdsa", Size: sz} | 		kr := &BasicKeyRequest{"ecdsa", sz} | ||||||
| 		priv, err := kr.Generate() | 		priv, err := kr.Generate() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Fatalf("%v", err) | 			t.Fatalf("%v", err) | ||||||
|  | @ -145,13 +144,13 @@ func TestRSAKeyGeneration(t *testing.T) { | ||||||
| 	var rsakey *rsa.PrivateKey | 	var rsakey *rsa.PrivateKey | ||||||
| 
 | 
 | ||||||
| 	for _, sz := range []int{2048, 3072, 4096} { | 	for _, sz := range []int{2048, 3072, 4096} { | ||||||
| 		kr := &KeyRequest{Algo: "rsa", Size: sz} | 		kr := &BasicKeyRequest{"rsa", sz} | ||||||
| 		priv, err := kr.Generate() | 		priv, err := kr.Generate() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Fatalf("%v", err) | 			t.Fatalf("%v", err) | ||||||
| 		} | 		} | ||||||
| 		rsakey = priv.(*rsa.PrivateKey) | 		rsakey = priv.(*rsa.PrivateKey) | ||||||
| 		if rsakey.PublicKey.N.BitLen() != kr.Size { | 		if rsakey.PublicKey.N.BitLen() != kr.Size() { | ||||||
| 			t.Fatal("Generated key has wrong size.") | 			t.Fatal("Generated key has wrong size.") | ||||||
| 		} | 		} | ||||||
| 		if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm { | 		if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm { | ||||||
|  | @ -160,26 +159,26 @@ func TestRSAKeyGeneration(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TestBadKeyRequest ensures that generating a key from a KeyRequest
 | // TestBadBasicKeyRequest ensures that generating a key from a BasicKeyRequest
 | ||||||
| // fails with an invalid algorithm, or an invalid RSA or ECDSA key
 | // fails with an invalid algorithm, or an invalid RSA or ECDSA key
 | ||||||
| // size. An invalid ECDSA key size is any size other than 256, 384, or
 | // size. An invalid ECDSA key size is any size other than 256, 384, or
 | ||||||
| // 521; an invalid RSA key size is any size less than 2048 bits.
 | // 521; an invalid RSA key size is any size less than 2048 bits.
 | ||||||
| func TestBadKeyRequest(t *testing.T) { | func TestBadBasicKeyRequest(t *testing.T) { | ||||||
| 	kr := &KeyRequest{Algo: "yolocrypto", Size: 1024} | 	kr := &BasicKeyRequest{"yolocrypto", 1024} | ||||||
| 	if _, err := kr.Generate(); err == nil { | 	if _, err := kr.Generate(); err == nil { | ||||||
| 		t.Fatal("Key generation should fail with invalid algorithm") | 		t.Fatal("Key generation should fail with invalid algorithm") | ||||||
| 	} else if sa := kr.SigAlgo(); sa != x509.UnknownSignatureAlgorithm { | 	} else if sa := kr.SigAlgo(); sa != x509.UnknownSignatureAlgorithm { | ||||||
| 		t.Fatal("The wrong signature algorithm was returned from SigAlgo!") | 		t.Fatal("The wrong signature algorithm was returned from SigAlgo!") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	kr.Algo = "ecdsa" | 	kr.A = "ecdsa" | ||||||
| 	if _, err := kr.Generate(); err == nil { | 	if _, err := kr.Generate(); err == nil { | ||||||
| 		t.Fatal("Key generation should fail with invalid key size") | 		t.Fatal("Key generation should fail with invalid key size") | ||||||
| 	} else if sa := kr.SigAlgo(); sa != x509.ECDSAWithSHA1 { | 	} else if sa := kr.SigAlgo(); sa != x509.ECDSAWithSHA1 { | ||||||
| 		t.Fatal("The wrong signature algorithm was returned from SigAlgo!") | 		t.Fatal("The wrong signature algorithm was returned from SigAlgo!") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	kr.Algo = "rsa" | 	kr.A = "rsa" | ||||||
| 	if _, err := kr.Generate(); err == nil { | 	if _, err := kr.Generate(); err == nil { | ||||||
| 		t.Fatal("Key generation should fail with invalid key size") | 		t.Fatal("Key generation should fail with invalid key size") | ||||||
| 	} else if sa := kr.SigAlgo(); sa != x509.SHA1WithRSA { | 	} else if sa := kr.SigAlgo(); sa != x509.SHA1WithRSA { | ||||||
|  | @ -188,9 +187,9 @@ func TestBadKeyRequest(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TestDefaultKeyRequest makes sure that certificate requests without
 | // TestDefaultBasicKeyRequest makes sure that certificate requests without
 | ||||||
| // explicit key requests fall back to the default key request.
 | // explicit key requests fall back to the default key request.
 | ||||||
| func TestDefaultKeyRequest(t *testing.T) { | func TestDefaultBasicKeyRequest(t *testing.T) { | ||||||
| 	var req = &CertificateRequest{ | 	var req = &CertificateRequest{ | ||||||
| 		Names: []Name{ | 		Names: []Name{ | ||||||
| 			{ | 			{ | ||||||
|  | @ -215,13 +214,14 @@ func TestDefaultKeyRequest(t *testing.T) { | ||||||
| 		t.Fatal("Bad private key was generated!") | 		t.Fatal("Bad private key was generated!") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	DefaultKeyRequest := NewBasicKeyRequest() | ||||||
| 	switch block.Type { | 	switch block.Type { | ||||||
| 	case "RSA PRIVATE KEY": | 	case "RSA PRIVATE KEY": | ||||||
| 		if DefaultKeyRequest.Algo != "rsa" { | 		if DefaultKeyRequest.Algo() != "rsa" { | ||||||
| 			t.Fatal("Invalid default key request.") | 			t.Fatal("Invalid default key request.") | ||||||
| 		} | 		} | ||||||
| 	case "EC PRIVATE KEY": | 	case "EC PRIVATE KEY": | ||||||
| 		if DefaultKeyRequest.Algo != "ecdsa" { | 		if DefaultKeyRequest.Algo() != "ecdsa" { | ||||||
| 			t.Fatal("Invalid default key request.") | 			t.Fatal("Invalid default key request.") | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -242,10 +242,7 @@ func TestRSACertRequest(t *testing.T) { | ||||||
| 		}, | 		}, | ||||||
| 		CN:         "cloudflare.com", | 		CN:         "cloudflare.com", | ||||||
| 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | ||||||
| 		KeyRequest: &KeyRequest{ | 		KeyRequest: &BasicKeyRequest{"rsa", 2048}, | ||||||
| 			Algo: "rsa", |  | ||||||
| 			Size: 2048, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
| 	_, _, err := ParseRequest(req) | 	_, _, err := ParseRequest(req) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -267,10 +264,7 @@ func TestBadCertRequest(t *testing.T) { | ||||||
| 		}, | 		}, | ||||||
| 		CN:         "cloudflare.com", | 		CN:         "cloudflare.com", | ||||||
| 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | ||||||
| 		KeyRequest: &KeyRequest{ | 		KeyRequest: &BasicKeyRequest{"yolo-crypto", 2048}, | ||||||
| 			Algo: "yolo-crypto", |  | ||||||
| 			Size: 2048, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
| 	_, _, err := ParseRequest(req) | 	_, _, err := ParseRequest(req) | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
|  | @ -305,10 +299,7 @@ func TestGenerator(t *testing.T) { | ||||||
| 		}, | 		}, | ||||||
| 		CN:         "cloudflare.com", | 		CN:         "cloudflare.com", | ||||||
| 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, | ||||||
| 		KeyRequest: &KeyRequest{ | 		KeyRequest: &BasicKeyRequest{"rsa", 2048}, | ||||||
| 			Algo: "rsa", |  | ||||||
| 			Size: 2048, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	csrBytes, _, err := g.ProcessRequest(req) | 	csrBytes, _, err := g.ProcessRequest(req) | ||||||
|  | @ -356,10 +347,7 @@ func TestBadGenerator(t *testing.T) { | ||||||
| 		}, | 		}, | ||||||
| 		// Missing CN
 | 		// Missing CN
 | ||||||
| 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | ||||||
| 		KeyRequest: &KeyRequest{ | 		KeyRequest: &BasicKeyRequest{"rsa", 2048}, | ||||||
| 			Algo: "rsa", |  | ||||||
| 			Size: 2048, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, _, err := g.ProcessRequest(missingCN) | 	_, _, err := g.ProcessRequest(missingCN) | ||||||
|  | @ -381,10 +369,7 @@ func TestWeakCSR(t *testing.T) { | ||||||
| 		}, | 		}, | ||||||
| 		CN:         "cloudflare.com", | 		CN:         "cloudflare.com", | ||||||
| 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"}, | ||||||
| 		KeyRequest: &KeyRequest{ | 		KeyRequest: &BasicKeyRequest{"rsa", 1024}, | ||||||
| 			Algo: "rsa", |  | ||||||
| 			Size: 1024, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
| 	g := &Generator{testValidator} | 	g := &Generator{testValidator} | ||||||
| 
 | 
 | ||||||
|  | @ -431,3 +416,76 @@ func TestIsNameEmpty(t *testing.T) { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestGenerate(t *testing.T) { | ||||||
|  | 	var req = &CertificateRequest{ | ||||||
|  | 		Names: []Name{ | ||||||
|  | 			{ | ||||||
|  | 				C:  "US", | ||||||
|  | 				ST: "California", | ||||||
|  | 				L:  "San Francisco", | ||||||
|  | 				O:  "CloudFlare", | ||||||
|  | 				OU: "Systems Engineering", | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		CN:         "cloudflare.com", | ||||||
|  | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, | ||||||
|  | 		KeyRequest: &BasicKeyRequest{"ecdsa", 256}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	key, err := req.KeyRequest.Generate() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	priv, ok := key.(crypto.Signer) | ||||||
|  | 	if !ok { | ||||||
|  | 		t.Fatal("Private key is not a signer.") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	csrPEM, err := Generate(priv, req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	_, _, err = helpers.ParseCSR(csrPEM) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestReGenerate(t *testing.T) { | ||||||
|  | 	var req = &CertificateRequest{ | ||||||
|  | 		Names: []Name{ | ||||||
|  | 			{ | ||||||
|  | 				C:  "US", | ||||||
|  | 				ST: "California", | ||||||
|  | 				L:  "San Francisco", | ||||||
|  | 				O:  "CloudFlare", | ||||||
|  | 				OU: "Systems Engineering", | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		CN:         "cloudflare.com", | ||||||
|  | 		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"}, | ||||||
|  | 		KeyRequest: &BasicKeyRequest{"ecdsa", 256}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	csr, key, err := ParseRequest(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	priv, err := helpers.ParsePrivateKeyPEM(key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	csr, err = Generate(priv, req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if _, _, err = helpers.ParseCSR(csr); err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -8,8 +8,10 @@ import ( | ||||||
| 	"crypto/ecdsa" | 	"crypto/ecdsa" | ||||||
| 	"crypto/rsa" | 	"crypto/rsa" | ||||||
| 	"crypto/x509" | 	"crypto/x509" | ||||||
|  | 	"encoding/asn1" | ||||||
| 	"encoding/pem" | 	"encoding/pem" | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"math/big" | ||||||
| 	//"fmt"
 | 	//"fmt"
 | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  | @ -231,6 +233,7 @@ func ParseSelfSignedCertificatePEM(certPEM []byte) (*x509.Certificate, error) { | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil { | 	if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil { | ||||||
| 		return nil, cferr.Wrap(cferr.CertificateError, cferr.VerifyFailed, err) | 		return nil, cferr.Wrap(cferr.CertificateError, cferr.VerifyFailed, err) | ||||||
| 	} | 	} | ||||||
|  | @ -312,3 +315,105 @@ func GetKeyDERFromPEM(in []byte) ([]byte, error) { | ||||||
| 
 | 
 | ||||||
| 	return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed) | 	return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // CheckSignature verifies a signature made by the key on a CSR, such
 | ||||||
|  | // as on the CSR itself.
 | ||||||
|  | func CheckSignature(csr *x509.CertificateRequest, algo x509.SignatureAlgorithm, signed, signature []byte) error { | ||||||
|  | 	var hashType crypto.Hash | ||||||
|  | 
 | ||||||
|  | 	switch algo { | ||||||
|  | 	case x509.SHA1WithRSA, x509.ECDSAWithSHA1: | ||||||
|  | 		hashType = crypto.SHA1 | ||||||
|  | 	case x509.SHA256WithRSA, x509.ECDSAWithSHA256: | ||||||
|  | 		hashType = crypto.SHA256 | ||||||
|  | 	case x509.SHA384WithRSA, x509.ECDSAWithSHA384: | ||||||
|  | 		hashType = crypto.SHA384 | ||||||
|  | 	case x509.SHA512WithRSA, x509.ECDSAWithSHA512: | ||||||
|  | 		hashType = crypto.SHA512 | ||||||
|  | 	default: | ||||||
|  | 		return x509.ErrUnsupportedAlgorithm | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !hashType.Available() { | ||||||
|  | 		return x509.ErrUnsupportedAlgorithm | ||||||
|  | 	} | ||||||
|  | 	h := hashType.New() | ||||||
|  | 
 | ||||||
|  | 	h.Write(signed) | ||||||
|  | 	digest := h.Sum(nil) | ||||||
|  | 
 | ||||||
|  | 	switch pub := csr.PublicKey.(type) { | ||||||
|  | 	case *rsa.PublicKey: | ||||||
|  | 		return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) | ||||||
|  | 	case *ecdsa.PublicKey: | ||||||
|  | 		ecdsaSig := new(struct{ R, S *big.Int }) | ||||||
|  | 		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { | ||||||
|  | 			return errors.New("x509: ECDSA signature contained zero or negative values") | ||||||
|  | 		} | ||||||
|  | 		if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) { | ||||||
|  | 			return errors.New("x509: ECDSA verification failure") | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return x509.ErrUnsupportedAlgorithm | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request.
 | ||||||
|  | func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) { | ||||||
|  | 	in = bytes.TrimSpace(in) | ||||||
|  | 	p, rest := pem.Decode(in) | ||||||
|  | 	if p != nil { | ||||||
|  | 		if p.Type != "CERTIFICATE REQUEST" { | ||||||
|  | 			return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		csr, err = x509.ParseCertificateRequest(p.Bytes) | ||||||
|  | 	} else { | ||||||
|  | 		csr, err = x509.ParseCertificateRequest(in) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, rest, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, rest, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return csr, rest, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SignerAlgo returns an X.509 signature algorithm corresponding to
 | ||||||
|  | // the crypto.Hash provided from a crypto.Signer.
 | ||||||
|  | func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm { | ||||||
|  | 	switch priv.Public().(type) { | ||||||
|  | 	case *rsa.PublicKey: | ||||||
|  | 		switch h { | ||||||
|  | 		case crypto.SHA512: | ||||||
|  | 			return x509.SHA512WithRSA | ||||||
|  | 		case crypto.SHA384: | ||||||
|  | 			return x509.SHA384WithRSA | ||||||
|  | 		case crypto.SHA256: | ||||||
|  | 			return x509.SHA256WithRSA | ||||||
|  | 		default: | ||||||
|  | 			return x509.SHA1WithRSA | ||||||
|  | 		} | ||||||
|  | 	case *ecdsa.PublicKey: | ||||||
|  | 		switch h { | ||||||
|  | 		case crypto.SHA512: | ||||||
|  | 			return x509.ECDSAWithSHA512 | ||||||
|  | 		case crypto.SHA384: | ||||||
|  | 			return x509.ECDSAWithSHA384 | ||||||
|  | 		case crypto.SHA256: | ||||||
|  | 			return x509.ECDSAWithSHA256 | ||||||
|  | 		default: | ||||||
|  | 			return x509.ECDSAWithSHA1 | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		return x509.UnknownSignatureAlgorithm | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -356,3 +356,25 @@ func TestParsePrivateKeyPEM(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // Imported from signers/local/testdata/
 | ||||||
|  | const ecdsaTestCSR = "testdata/ecdsa256.csr" | ||||||
|  | 
 | ||||||
|  | func TestParseCSRPEM(t *testing.T) { | ||||||
|  | 	in, err := ioutil.ReadFile(ecdsaTestCSR) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	_, _, err = ParseCSR(in) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("%v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	in[12]++ | ||||||
|  | 	_, _, err = ParseCSR(in) | ||||||
|  | 	if err == nil { | ||||||
|  | 		t.Fatalf("Expected an invalid CSR.") | ||||||
|  | 	} | ||||||
|  | 	in[12]-- | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/pkcs11uri/pkcs11uri.go
								
								
									generated
								
								
									vendored
								
								
							
							
						
						
									
										10
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/pkcs11uri/pkcs11uri.go
								
								
									generated
								
								
									vendored
								
								
							|  | @ -10,8 +10,8 @@ import ( | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key" | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func setIfPresent(val url.Values, k string, target *string) { | func setIfPresent(val url.Values, k string, target *string) { | ||||||
|  | @ -27,13 +27,13 @@ var ErrInvalidURI = errors.New(errors.PrivateKeyError, errors.ParseFailed) | ||||||
| // ParsePKCS11URI parses a PKCS #11 URI into a PKCS #11
 | // ParsePKCS11URI parses a PKCS #11 URI into a PKCS #11
 | ||||||
| // configuration. Note that the module path will override the module
 | // configuration. Note that the module path will override the module
 | ||||||
| // name if present.
 | // name if present.
 | ||||||
| func ParsePKCS11URI(uri string) (*pkcs11.Config, error) { | func ParsePKCS11URI(uri string) (*pkcs11key.Config, error) { | ||||||
| 	u, err := url.Parse(uri) | 	u, err := url.Parse(uri) | ||||||
| 	if err != nil || u.Scheme != "pkcs11" { | 	if err != nil || u.Scheme != "pkcs11" { | ||||||
| 		return nil, ErrInvalidURI | 		return nil, ErrInvalidURI | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	c := new(pkcs11.Config) | 	c := new(pkcs11key.Config) | ||||||
| 
 | 
 | ||||||
| 	pk11PAttr, err := url.ParseQuery(u.Opaque) | 	pk11PAttr, err := url.ParseQuery(u.Opaque) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -44,11 +44,11 @@ func ParsePKCS11URI(uri string) (*pkcs11.Config, error) { | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, ErrInvalidURI | 		return nil, ErrInvalidURI | ||||||
| 	} | 	} | ||||||
| 	setIfPresent(pk11PAttr, "token", &c.Token) | 	setIfPresent(pk11PAttr, "token", &c.TokenLabel) | ||||||
|  | 	setIfPresent(pk11PAttr, "object", &c.PrivateKeyLabel) | ||||||
| 	setIfPresent(pk11QAttr, "module-name", &c.Module) | 	setIfPresent(pk11QAttr, "module-name", &c.Module) | ||||||
| 	setIfPresent(pk11QAttr, "module-path", &c.Module) | 	setIfPresent(pk11QAttr, "module-path", &c.Module) | ||||||
| 	setIfPresent(pk11QAttr, "pin-value", &c.PIN) | 	setIfPresent(pk11QAttr, "pin-value", &c.PIN) | ||||||
| 	setIfPresent(pk11PAttr, "slot-description", &c.Label) |  | ||||||
| 
 | 
 | ||||||
| 	var pinSourceURI string | 	var pinSourceURI string | ||||||
| 	setIfPresent(pk11QAttr, "pin-source", &pinSourceURI) | 	setIfPresent(pk11QAttr, "pin-source", &pinSourceURI) | ||||||
|  |  | ||||||
							
								
								
									
										34
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/pkcs11uri/pkcs11uri_test.go
								
								
									generated
								
								
									vendored
								
								
							
							
						
						
									
										34
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/pkcs11uri/pkcs11uri_test.go
								
								
									generated
								
								
									vendored
								
								
							|  | @ -4,15 +4,15 @@ import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type pkcs11UriTest struct { | type pkcs11UriTest struct { | ||||||
| 	URI    string | 	URI    string | ||||||
| 	Config *pkcs11.Config | 	Config *pkcs11key.Config | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func cmpConfigs(a, b *pkcs11.Config) bool { | func cmpConfigs(a, b *pkcs11key.Config) bool { | ||||||
| 	if a == nil { | 	if a == nil { | ||||||
| 		if b == nil { | 		if b == nil { | ||||||
| 			return true | 			return true | ||||||
|  | @ -25,12 +25,12 @@ func cmpConfigs(a, b *pkcs11.Config) bool { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return (a.Module == b.Module) && | 	return (a.Module == b.Module) && | ||||||
| 		(a.Token == b.Token) && | 		(a.TokenLabel == b.TokenLabel) && | ||||||
| 		(a.PIN == b.PIN) && | 		(a.PIN == b.PIN) && | ||||||
| 		(a.Label == b.Label) | 		(a.PrivateKeyLabel == b.PrivateKeyLabel) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func diffConfigs(want, have *pkcs11.Config) { | func diffConfigs(want, have *pkcs11key.Config) { | ||||||
| 	if have == nil && want != nil { | 	if have == nil && want != nil { | ||||||
| 		fmt.Printf("Expected config, have nil.") | 		fmt.Printf("Expected config, have nil.") | ||||||
| 		return | 		return | ||||||
|  | @ -45,9 +45,9 @@ func diffConfigs(want, have *pkcs11.Config) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	diff("Module", want.Module, have.Module) | 	diff("Module", want.Module, have.Module) | ||||||
| 	diff("Token", want.Token, have.Token) | 	diff("TokenLabel", want.TokenLabel, have.TokenLabel) | ||||||
| 	diff("PIN", want.PIN, have.PIN) | 	diff("PIN", want.PIN, have.PIN) | ||||||
| 	diff("Label", want.Label, have.Label) | 	diff("PrivateKeyLabel", want.PrivateKeyLabel, have.PrivateKeyLabel) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Config from PKCS #11 signer | /* Config from PKCS #11 signer | ||||||
|  | @ -61,18 +61,18 @@ type Config struct { | ||||||
| 
 | 
 | ||||||
| var pkcs11UriCases = []pkcs11UriTest{ | var pkcs11UriCases = []pkcs11UriTest{ | ||||||
| 	{"pkcs11:token=Software%20PKCS%2311%20softtoken;manufacturer=Snake%20Oil,%20Inc.?pin-value=the-pin", | 	{"pkcs11:token=Software%20PKCS%2311%20softtoken;manufacturer=Snake%20Oil,%20Inc.?pin-value=the-pin", | ||||||
| 		&pkcs11.Config{ | 		&pkcs11key.Config{ | ||||||
| 			Token: "Software PKCS#11 softtoken", | 			TokenLabel: "Software PKCS#11 softtoken", | ||||||
| 			PIN:        "the-pin", | 			PIN:        "the-pin", | ||||||
| 		}}, | 		}}, | ||||||
| 	{"pkcs11:slot-description=Sun%20Metaslot", | 	{"pkcs11:token=Sun%20Token", | ||||||
| 		&pkcs11.Config{ | 		&pkcs11key.Config{ | ||||||
| 			Label: "Sun Metaslot", | 			TokenLabel: "Sun Token", | ||||||
| 		}}, | 		}}, | ||||||
| 	{"pkcs11:slot-description=test-label;token=test-token?pin-source=file:testdata/pin&module-name=test-module", | 	{"pkcs11:object=test-privkey;token=test-token?pin-source=file:testdata/pin&module-name=test-module", | ||||||
| 		&pkcs11.Config{ | 		&pkcs11key.Config{ | ||||||
| 			Label:  "test-label", | 			PrivateKeyLabel: "test-privkey", | ||||||
| 			Token:  "test-token", | 			TokenLabel:      "test-token", | ||||||
| 			PIN:             "123456", | 			PIN:             "123456", | ||||||
| 			Module:          "test-module", | 			Module:          "test-module", | ||||||
| 		}}, | 		}}, | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/ecdsa256.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/ecdsa256.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | -----BEGIN CERTIFICATE REQUEST----- | ||||||
|  | MIIBgTCCASgCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl | ||||||
|  | MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh | ||||||
|  | bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl | ||||||
|  | LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBn9Ldie6BOcMHezn2dPuYqW | ||||||
|  | z/NoLYMLGNBqhOxUyEidYClI0JW2pWyUgT3A2UazFp1WgE94y7Z+2YlfRz+vcrKg | ||||||
|  | PzA9BgkqhkiG9w0BCQ4xMDAuMCwGA1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3 | ||||||
|  | d3djbG91ZGZsYXJlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBM+QRxe8u6rkdr10Jy | ||||||
|  | cxbR6NxrGrNeg5QqiOqF96JEmgIgDbtjd5e3y3I8W/+ih2us3WtMxgnTXfqPd48i | ||||||
|  | VLcv28Q= | ||||||
|  | -----END CERTIFICATE REQUEST----- | ||||||
|  | @ -1 +1 @@ | ||||||
| {"cert":"-----BEGIN CERTIFICATE-----\nMIIEBjCCAvCgAwIBAgIIcoeD7FP4p0gwCwYJKoZIhvcNAQELMIGQMQswCQYDVQQG\nEwJVUzEeMBwGA1UEChMVSW50ZXJuZXQgV2lkZ2V0cywgTExDMR4wHAYDVQQLExVD\nZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzAR\nBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAMTC2V4YW1wbGUuY29tMB4XDTE1MDMy\nMzIwMTcwMloXDTE1MDMyMzIwMjIwMlowgZAxCzAJBgNVBAYTAlVTMR4wHAYDVQQK\nExVJbnRlcm5ldCBXaWRnZXRzLCBMTEMxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1\ndGhvcml0eTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv\ncm5pYTEUMBIGA1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQC/S+yLMwj5TEIWSujzOf3VBMCyiW+KM17fvSK6Wp14OElFs53G\nNNRVJDkIOyx66I29YqvYTO28WyLX3X8z8tS3hH8C9Bp/lG5X644hiQpl5vHSJfxa\nQdvtJZevY6lwnz9JDha1X0P7XzHeyJVC8u3Uq8i4X7t2GC23p0Jz5hEs6YBn6cQa\nui1I40U9teNUPE4ofUOt2EUx2uDiRs0+IOy5gM/GH7XDv88eWwSm/loqwYp5CdAv\n0/jnPqisqen0KXEQNFgZJZSzZy2a1GE4Ie/yc9R8udnkUd5pgIk26T4UDSpNVnDA\n5N7mH2MpcQ4l1ErTVk8WWrM+6X5UVIkWA56LAgMBAAGjZjBkMA4GA1UdDwEB/wQE\nAwIABjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBR8CfC68fIBAkJcjFOD\n6SDYLUTanTAfBgNVHSMEGDAWgBR8CfC68fIBAkJcjFOD6SDYLUTanTALBgkqhkiG\n9w0BAQsDggEBACZdSOd9C+ZiVGSqK113CvvQWMVxgEiprbQ+p2jJ+tmcZdAEDgDO\nEEdjPs1ygdhwJwiQL1C5Ak4Xc91aamP2dZtMlM02UVzTrjsOyC7FShq238pyaeQX\nzXyOOSnriMeuJvipLiStk1WhrbRkq1Zfy5CmX6FYd1dfuljwoDgfAY9GtCi0T6MY\n6vu9f8/S2ei4sTtqkF2/KbBq3K17WqsMmDxCYMWxBaY1z92i01lypPw3tM3k4Gkn\nJnil6RYlqg9odhazZcFXsNNywxg2S2Q2pJ1JLGDypgBpqzMQjd7zP6WOz9MTP8yK\n+V2sF/dDlAQCvl8EPvigqCCOXtL6uHYo0Fw=\n-----END CERTIFICATE-----\n","key":"-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAv0vsizMI+UxCFkro8zn91QTAsolvijNe370iulqdeDhJRbOd\nxjTUVSQ5CDsseuiNvWKr2EztvFsi191/M/LUt4R/AvQaf5RuV+uOIYkKZebx0iX8\nWkHb7SWXr2OpcJ8/SQ4WtV9D+18x3siVQvLt1KvIuF+7dhgtt6dCc+YRLOmAZ+nE\nGrotSONFPbXjVDxOKH1DrdhFMdrg4kbNPiDsuYDPxh+1w7/PHlsEpv5aKsGKeQnQ\nL9P45z6orKnp9ClxEDRYGSWUs2ctmtRhOCHv8nPUfLnZ5FHeaYCJNuk+FA0qTVZw\nwOTe5h9jKXEOJdRK01ZPFlqzPul+VFSJFgOeiwIDAQABAoIBAEzKaZYnUn7gwda5\nE3Iv4VlVoxUIXqIXpQojnoE4RuYvkhpM1BTwuBvFgq9vMZfVKrDPnzQhDX4DB6Wn\n4Jw16nYQ1fuVid2U9AaPJGsJ3Aa0AnbdkMOalHJKGO3rD+WJx5nH8g20xFFwEVDh\nLCnH4vjwTI7WvyXU5uVGW0KzJEnmbpjupMo+3IKSUdZyZspAc2vZby+bU18U7PO2\nfsyW7aZjQ0b2XFKbWpw+RD/HOskBImOqoL9AAzvXEaxFR3mz4OQBtUlzEiogr0/6\ngBNTbyIVSE+0hodtLxJMhi+xIFeoGCyYdpONU3mqKcYjnV4mHfLX2+Sn4hTJtaLg\n7VHyiKECgYEAwC+4RK1E/UU9nvEgaUowpmAtnk40g31ACylOmpAiHaBaJfZ2JToe\nSwd60oFZ5QEA/zoch1niUwgtj4Bn+Iv/sRD3N60DuLg5F+S+0qH7viZb5jAsIYmP\ntF7+nMd6iID+vXhXqL/ElJczGldKm+wKPV9n8KcdvHwDySvsy//WC0cCgYEA/tCR\nHbiLbMyA+stu7i5AdVWsSxmNipD8pjrI6509zerwnwvwX5nxagO3hBmev/jJgJKu\nL3ptZotR5CpcS/PxmNdRHumeQzvN5AnUefB037tQOtocPIAWwnh4a+hf4QtdXRmm\nbtSZPDBaIdEL+6XEpCfHdSktj/8nJ0aftW39rJ0CgYA7hgwiaS/26Z0ePzx0n9/V\nh/BZGYu2NfLCAjcwM/f9CQ8ituT8vrVnM5fc3udCwD7YzdzMJxCr+tpxmamaF3JI\nGyMWgWWnrpcwSU642iaoTCUmdEEW2g5CJTHiyP2wjZNYh49O2qY+B15yiBq5lC/P\ntl7w8DGLkTVy90HOJRzcPQKBgF1rY7iMvvkNZMANs0a5SEJ8PWVvIdhKXYYoCR9w\nj4cd+kelHeQ+0SY35KEWr3/cGyv7GscnUFKHA2fuK9ZgwhNx5Ti7F524oDxZaj+m\na4LW7owVCMMZhr6XYjbVg8lC3GDUlZMOeHt7kp/RP15sINK6DsMibKTdO6KHnufq\nQlV1AoGBAKeRFcw0jSB0PWEVHPDF4pCSz/vhoX/hy0OQN13QWLFhgt/rmTWOCFuJ\nSvIde8oM2pD5f8ZmxzMGkknEnrdX7zz/tE4roImep9G49BbetHGdWVu/TvvDyvXM\nzi//6WQzpjjqQxrl4q7B1tJ4A71fKN6V2u+qSdYg/t31EfE47lCQ\n-----END RSA PRIVATE KEY-----\n"} | {"cert":"-----BEGIN CERTIFICATE-----\nMIIECjCCAvKgAwIBAgIIIrWBQ2reGCQwDQYJKoZIhvcNAQELBQAwgZAxCzAJBgNV\nBAYTAlVTMR4wHAYDVQQKExVJbnRlcm5ldCBXaWRnZXRzLCBMTEMxHjAcBgNVBAsT\nFUNlcnRpZmljYXRlIEF1dGhvcml0eTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET\nMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTUw\nOTA5MjExNjAwWhcNMTUwOTA5MjExNjAwWjCBkDELMAkGA1UEBhMCVVMxHjAcBgNV\nBAoTFUludGVybmV0IFdpZGdldHMsIExMQzEeMBwGA1UECxMVQ2VydGlmaWNhdGUg\nQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxp\nZm9ybmlhMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBALOFN1p4aaMQKqInRanzmf05CD4kYKKVygggOHhD3ZgwFgIG\n20Z0dlTHStY/UvY+2qkpB1Bp9trmys9YvPzt5ElX2szZ2deZc0TWvzZeuZDQVsbx\n0Ea6RGxRnEEoMrpaRFoe2TOKSVKW+SzLC/eoNUoxsZVo6cNsU4BeGqExOWCDFzjd\nCRLJeXqafYeL1dUiXZ028tOZVWLIjaLu3FKENHeDB36gr99KckFdeDnqaAVvu66V\nbF5QGvIv2RmK9y3cq7rIizYfayi/dBS8/AY31OOHcEGsVTZYjqB/s9aIocCOzfvQ\nV5++QdkDiYhIwokB3fT5b4wIb8CLr0GUnHnslnMCAwEAAaNmMGQwDgYDVR0PAQH/\nBAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFCL83Uiwa3VGSXwD\nf8XKgu1l+nX8MB8GA1UdIwQYMBaAFCL83Uiwa3VGSXwDf8XKgu1l+nX8MA0GCSqG\nSIb3DQEBCwUAA4IBAQCRP7HK4JHxY4uYE3VBkx5SSQouZrnpQCOnUhSof3vi5nk0\nlhfIU7nbS6HVyQC4mY47gDrBlKwTr++Kw9BKyK9EgfVWhct8vszcRexZk5mmO3yi\n3s4kqD158SP0t5AMahHGK/VviD/Id4kaX1PIPHW3TfU3Ly4LP6d/NlloaXc8qrsg\nKJO+AXTy9xnEkjtq7lvnP3JLwA1Y+nozqkp46kQv0K+Nz+MBqN5De12I9J7T0k6h\nij4MsiraPdeij6d1cp+OEW8DPe+MCIBYAvbJXtQY5zYPB2/F6JJHMeQ9AmluvUFn\nD3ipCSVbw1Tgpp8xcx+4rt9Vq6Oo8pGi4JR3C7TN\n-----END CERTIFICATE-----\n","csr":"-----BEGIN CERTIFICATE REQUEST-----\nMIIDAjCCAeoCAQAwgZAxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVJbnRlcm5ldCBX\naWRnZXRzLCBMTEMxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEWMBQG\nA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UE\nAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz\nhTdaeGmjECqiJ0Wp85n9OQg+JGCilcoIIDh4Q92YMBYCBttGdHZUx0rWP1L2Ptqp\nKQdQafba5srPWLz87eRJV9rM2dnXmXNE1r82XrmQ0FbG8dBGukRsUZxBKDK6WkRa\nHtkziklSlvksywv3qDVKMbGVaOnDbFOAXhqhMTlggxc43QkSyXl6mn2Hi9XVIl2d\nNvLTmVViyI2i7txShDR3gwd+oK/fSnJBXXg56mgFb7uulWxeUBryL9kZivct3Ku6\nyIs2H2sov3QUvPwGN9Tjh3BBrFU2WI6gf7PWiKHAjs370FefvkHZA4mISMKJAd30\n+W+MCG/Ai69BlJx57JZzAgMBAAGgLDAqBgkqhkiG9w0BCQ4xHTAbMBkGA1UdEQQS\nMBCCDmNhLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQA2E/lSvOtUZjOj\ncOAcALpCVLLTSRdqF7745jSqIrHV8RuB+V6HFi55qoFzCKfJbc81SUqX7DhzoUtP\nNjdq5RfhEh/kWw3GeIN90Y5thVDm0i19A7GY+maJXMjw3LVWlKIo9a7rCOQvCi3O\nkA0QGO1Rc1d6/MneoWUR2tUHjJ83FvO089RaDUQhYpInBXV3GQByJGJeF8USJ/wS\nXy+SLDkaG9mC0TJwWNpldGoZQ57h/QeLtl2wfK3sLga5eVuQO0Lnzt6W3tYvvSAO\nckN/hrTMFMJ/vXHFUPXk8AYUBt0FqgYYHR5JxA9Wl2+Fr+Duw7Qee7/kcbwhbo1M\nLe9GgT/c\n-----END CERTIFICATE REQUEST-----\n","key":"-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAs4U3WnhpoxAqoidFqfOZ/TkIPiRgopXKCCA4eEPdmDAWAgbb\nRnR2VMdK1j9S9j7aqSkHUGn22ubKz1i8/O3kSVfazNnZ15lzRNa/Nl65kNBWxvHQ\nRrpEbFGcQSgyulpEWh7ZM4pJUpb5LMsL96g1SjGxlWjpw2xTgF4aoTE5YIMXON0J\nEsl5epp9h4vV1SJdnTby05lVYsiNou7cUoQ0d4MHfqCv30pyQV14OepoBW+7rpVs\nXlAa8i/ZGYr3LdyrusiLNh9rKL90FLz8BjfU44dwQaxVNliOoH+z1oihwI7N+9BX\nn75B2QOJiEjCiQHd9PlvjAhvwIuvQZSceeyWcwIDAQABAoIBAQCYD0cLwuL31EHI\niCtiAY12CFELEhUoomg26dPrStDwkAqUPOqPiyaQOR8SyyCipCrjDnW7j4YhdUxk\nxW2PcJHl7hzPV9hF3xzcOmpMy3+zQkW+ziT1Q+GhPp90MXCGmN881tRz67af1nHJ\nl1PTuw8ogV9Ch1M6zQ8NtKgp0WAgdn2YlkVrYv9/JaOZdh7ewNQPs+V68bC8tmmz\nEj0kuH06Lzr3zxfxOgAq8Xrv8b5GmFNjcRPOu5WWCRKt26FSwAcI/U5AXRuqVr8o\nthMiXKPA+RMSSy7bDF1EOFYdNyrWaLEzyrKLSxTXTvOT5kIfwVWKTTzdNug/BaYy\neesqkgtBAoGBAOafPTvJHYLHuyb11X2FYblvkLaw+orWvdy1E2sV62M3YiloOp5R\neWteEptvsEjo0ZXZyYqOK5WHsbkdTbPE7QPctKIYdVdztPb+3wWHM9hP1kGWuohW\n+S/kVIwf+ijH10Q3wQPgtsIGrj0Q/rkizD6qqmKz8gNizRwX2k3kkp/1AoGBAMdG\nabBuC9XHxFtVIEzHSXbVn38Z6tjxURcUK7hob8iRfl4JXbHtEKkoM2iIpY/a4YrA\nvjLBy0tNWnurTdT/Md7L3pqU4wVlMY0i5ysae7/vm2WV9ePdcHM1Oa4gFTSL3dW1\nLI3TLwxDD3vlqhP/Js3CMq7wtvTE1T1sWxjiLOPHAoGBAI9t49Bl8SOgAoZliARL\nyw5gE3l7siZdDbHRMCV+eWm4TSWBfEtwUnpzBFGFcfa2TXrL+ytf5j1WKjL9xZCT\nXfDz96eEXJ4qCRdARgYTIyxZ4t/h1Vrr9IhTkj2fuZ5ZQ0la/4Dg5ejf7Mdv5WvQ\n94PV8qf2UALJFNVvBEdDa+ltAoGAVjSYvhEtH4M254fQ3EYN+tF5GSPeG5FxUfmQ\n3EqZqPt/3jBRDwqN/Y99hcgvTycSENNGtHBvgJjq/rrhhbYMHeS13Mtx1kCrifHC\nbTwcsrB12iFgaP2/iqdI15HbeorTIYMpzgTAwp40EZYN2G61m6daA6Hwk7yevt6k\nHgSiBLsCgYEAoou8wIMi0+zyUgIo8MXYhexJFuYvEdHeyYvWN/FA4j/DZelixgW9\no4a0M9yOXStvjUUpG/TpaceJGqtwXk9bMBZML05fT7Im/3Qmh+44fF/a0q0Ard2N\nzdlIuaKlvcK5a6jD+mcN9vzOi4iuGUm1OhfTvHD/IS/rG4r6XhahHm4=\n-----END RSA PRIVATE KEY-----\n"} | ||||||
|  |  | ||||||
|  | @ -27,9 +27,9 @@ const ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
| 	keyRequest = csr.KeyRequest{ | 	keyRequest = csr.BasicKeyRequest{ | ||||||
| 		Algo: "rsa", | 		A: "rsa", | ||||||
| 		Size: 2048, | 		S: 2048, | ||||||
| 	} | 	} | ||||||
| 	CAConfig = csr.CAConfig{ | 	CAConfig = csr.CAConfig{ | ||||||
| 		PathLength: 1, | 		PathLength: 1, | ||||||
|  | @ -249,33 +249,8 @@ func TestCreateSelfSignedCert(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| 	// --- TEST: Create a self-signed certificate from a CSR. --- //
 | 	// --- TEST: Create a self-signed certificate from a CSR. --- //
 | ||||||
| 
 | 
 | ||||||
| 	// Make the request we will use to generate the certificate.
 |  | ||||||
| 	keyRequest := csr.KeyRequest{ |  | ||||||
| 		Algo: "rsa", |  | ||||||
| 		Size: 2048, |  | ||||||
| 	} |  | ||||||
| 	CAConfig := csr.CAConfig{ |  | ||||||
| 		PathLength: 1, |  | ||||||
| 		Expiry:     "1/1/2015", |  | ||||||
| 	} |  | ||||||
| 	request := csr.CertificateRequest{ |  | ||||||
| 		CN: "example.com", |  | ||||||
| 		Names: []csr.Name{ |  | ||||||
| 			{ |  | ||||||
| 				C:  "US", |  | ||||||
| 				ST: "California", |  | ||||||
| 				L:  "San Francisco", |  | ||||||
| 				O:  "Internet Widgets, LLC", |  | ||||||
| 				OU: "Certificate Authority", |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		Hosts:      []string{"ca.example.com"}, |  | ||||||
| 		KeyRequest: &keyRequest, |  | ||||||
| 		CA:         &CAConfig, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Generate a self-signed certificate from the request.
 | 	// Generate a self-signed certificate from the request.
 | ||||||
| 	encodedCertFromCode, _, err := CreateSelfSignedCert(request) | 	encodedCertFromCode, _, err := CreateSelfSignedCert(CARequest) | ||||||
| 	checkError(err, t) | 	checkError(err, t) | ||||||
| 
 | 
 | ||||||
| 	// Now compare to a pre-made certificate made using a JSON file with the
 | 	// Now compare to a pre-made certificate made using a JSON file with the
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| package config | package config | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -14,15 +15,5 @@ type Config struct { | ||||||
| 	ResponderCertFile string | 	ResponderCertFile string | ||||||
| 	KeyFile           string | 	KeyFile           string | ||||||
| 	Interval          time.Duration | 	Interval          time.Duration | ||||||
| 	PKCS11 PKCS11Config | 	PKCS11            pkcs11key.Config | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // PKCS11Config contains information specific to setting up a PKCS11 OCSP
 |  | ||||||
| // signer.
 |  | ||||||
| type PKCS11Config struct { |  | ||||||
| 	Module string |  | ||||||
| 	Token  string |  | ||||||
| 	PIN    string |  | ||||||
| 	Label  string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -20,7 +20,9 @@ import ( | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/golang.org/x/crypto/ocsp" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/golang.org/x/crypto/ocsp" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var statusCode = map[string]int{ | // StatusCode is a map between string statuses sent by cli/api
 | ||||||
|  | // to ocsp int statuses
 | ||||||
|  | var StatusCode = map[string]int{ | ||||||
| 	"good":    ocsp.Good, | 	"good":    ocsp.Good, | ||||||
| 	"revoked": ocsp.Revoked, | 	"revoked": ocsp.Revoked, | ||||||
| 	"unknown": ocsp.Unknown, | 	"unknown": ocsp.Unknown, | ||||||
|  | @ -122,7 +124,7 @@ func (s StandardSigner) Sign(req SignRequest) ([]byte, error) { | ||||||
| 	thisUpdate := time.Now().Truncate(time.Hour) | 	thisUpdate := time.Now().Truncate(time.Hour) | ||||||
| 	nextUpdate := thisUpdate.Add(s.interval) | 	nextUpdate := thisUpdate.Add(s.interval) | ||||||
| 
 | 
 | ||||||
| 	status, ok := statusCode[req.Status] | 	status, ok := StatusCode[req.Status] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		return nil, cferr.New(cferr.OCSPError, cferr.InvalidStatus) | 		return nil, cferr.New(cferr.OCSPError, cferr.InvalidStatus) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -31,8 +31,11 @@ func NewPKCS11Signer(cfg ocspConfig.Config) (ocsp.Signer, error) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	PKCS11 := cfg.PKCS11 | 	PKCS11 := cfg.PKCS11 | ||||||
| 	priv, err := pkcs11key.New(PKCS11.Module, PKCS11.Token, PKCS11.PIN, | 	priv, err := pkcs11key.New( | ||||||
| 		PKCS11.Label) | 		PKCS11.Module, | ||||||
|  | 		PKCS11.TokenLabel, | ||||||
|  | 		PKCS11.PIN, | ||||||
|  | 		PKCS11.PrivateKeyLabel) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) | 		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -52,6 +52,10 @@ func NewSourceFromFile(responseFile string) (Source, error) { | ||||||
| 	responsesB64 := regexp.MustCompile("\\s").Split(string(fileContents), -1) | 	responsesB64 := regexp.MustCompile("\\s").Split(string(fileContents), -1) | ||||||
| 	src := InMemorySource{} | 	src := InMemorySource{} | ||||||
| 	for _, b64 := range responsesB64 { | 	for _, b64 := range responsesB64 { | ||||||
|  | 		// if the line/space is empty just skip
 | ||||||
|  | 		if b64 == "" { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
| 		der, tmpErr := base64.StdEncoding.DecodeString(b64) | 		der, tmpErr := base64.StdEncoding.DecodeString(b64) | ||||||
| 		if tmpErr != nil { | 		if tmpErr != nil { | ||||||
| 			log.Errorf("Base64 decode error on: %s", b64) | 			log.Errorf("Base64 decode error on: %s", b64) | ||||||
|  |  | ||||||
|  | @ -14,20 +14,11 @@ import ( | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Config contains configuration information required to use a PKCS
 |  | ||||||
| // #11 key.
 |  | ||||||
| type Config struct { |  | ||||||
| 	Module string |  | ||||||
| 	Token  string |  | ||||||
| 	PIN    string |  | ||||||
| 	Label  string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Enabled is set to true if PKCS #11 support is present.
 | // Enabled is set to true if PKCS #11 support is present.
 | ||||||
| const Enabled = true | const Enabled = true | ||||||
| 
 | 
 | ||||||
| // New returns a new PKCS #11 signer.
 | // New returns a new PKCS #11 signer.
 | ||||||
| func New(caCertFile string, policy *config.Signing, cfg *Config) (signer.Signer, error) { | func New(caCertFile string, policy *config.Signing, cfg *pkcs11key.Config) (signer.Signer, error) { | ||||||
| 	if cfg == nil { | 	if cfg == nil { | ||||||
| 		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) | 		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) | ||||||
| 	} | 	} | ||||||
|  | @ -43,7 +34,7 @@ func New(caCertFile string, policy *config.Signing, cfg *Config) (signer.Signer, | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	priv, err := pkcs11key.New(cfg.Module, cfg.Token, cfg.PIN, cfg.Label) | 	priv, err := pkcs11key.New(cfg.Module, cfg.TokenLabel, cfg.PIN, cfg.PrivateKeyLabel) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) | 		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ import ( | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config" | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr" | ||||||
| 	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | 	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | ||||||
|  | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers" | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/info" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/info" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -147,7 +148,7 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature) | 	err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err) | 		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err) | ||||||
| 		return | 		return | ||||||
|  | @ -165,51 +166,6 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CheckSignature verifies a signature made by the key on a CSR, such
 |  | ||||||
| // as on the CSR itself.
 |  | ||||||
| func CheckSignature(csr *x509.CertificateRequest, algo x509.SignatureAlgorithm, signed, signature []byte) error { |  | ||||||
| 	var hashType crypto.Hash |  | ||||||
| 
 |  | ||||||
| 	switch algo { |  | ||||||
| 	case x509.SHA1WithRSA, x509.ECDSAWithSHA1: |  | ||||||
| 		hashType = crypto.SHA1 |  | ||||||
| 	case x509.SHA256WithRSA, x509.ECDSAWithSHA256: |  | ||||||
| 		hashType = crypto.SHA256 |  | ||||||
| 	case x509.SHA384WithRSA, x509.ECDSAWithSHA384: |  | ||||||
| 		hashType = crypto.SHA384 |  | ||||||
| 	case x509.SHA512WithRSA, x509.ECDSAWithSHA512: |  | ||||||
| 		hashType = crypto.SHA512 |  | ||||||
| 	default: |  | ||||||
| 		return x509.ErrUnsupportedAlgorithm |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if !hashType.Available() { |  | ||||||
| 		return x509.ErrUnsupportedAlgorithm |  | ||||||
| 	} |  | ||||||
| 	h := hashType.New() |  | ||||||
| 
 |  | ||||||
| 	h.Write(signed) |  | ||||||
| 	digest := h.Sum(nil) |  | ||||||
| 
 |  | ||||||
| 	switch pub := csr.PublicKey.(type) { |  | ||||||
| 	case *rsa.PublicKey: |  | ||||||
| 		return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) |  | ||||||
| 	case *ecdsa.PublicKey: |  | ||||||
| 		ecdsaSig := new(struct{ R, S *big.Int }) |  | ||||||
| 		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { |  | ||||||
| 			return errors.New("x509: ECDSA signature contained zero or negative values") |  | ||||||
| 		} |  | ||||||
| 		if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) { |  | ||||||
| 			return errors.New("x509: ECDSA verification failure") |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	return x509.ErrUnsupportedAlgorithm |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type subjectPublicKeyInfo struct { | type subjectPublicKeyInfo struct { | ||||||
| 	Algorithm        pkix.AlgorithmIdentifier | 	Algorithm        pkix.AlgorithmIdentifier | ||||||
| 	SubjectPublicKey asn1.BitString | 	SubjectPublicKey asn1.BitString | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/universal/universal.go
								
								
									generated
								
								
									vendored
								
								
							
							
						
						
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/universal/universal.go
								
								
									generated
								
								
									vendored
								
								
							|  | @ -3,6 +3,7 @@ package universal | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config" | ||||||
|  | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key" | ||||||
| 	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | 	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors" | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer" | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local" | 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local" | ||||||
|  | @ -38,12 +39,12 @@ func fileBackedSigner(root *Root, policy *config.Signing) (signer.Signer, bool, | ||||||
| // options in the root.
 | // options in the root.
 | ||||||
| func pkcs11Signer(root *Root, policy *config.Signing) (signer.Signer, bool, error) { | func pkcs11Signer(root *Root, policy *config.Signing) (signer.Signer, bool, error) { | ||||||
| 	module := root.Config["pkcs11-module"] | 	module := root.Config["pkcs11-module"] | ||||||
| 	token := root.Config["pkcs11-token"] | 	tokenLabel := root.Config["pkcs11-token-label"] | ||||||
| 	label := root.Config["pkcs11-label"] | 	privateKeyLabel := root.Config["pkcs11-private-key-label"] | ||||||
| 	userPIN := root.Config["pkcs11-user-pin"] | 	userPIN := root.Config["pkcs11-user-pin"] | ||||||
| 	certFile := root.Config["cert-file"] | 	certFile := root.Config["cert-file"] | ||||||
| 
 | 
 | ||||||
| 	if module == "" && token == "" && label == "" && userPIN == "" { | 	if module == "" && tokenLabel == "" && privateKeyLabel == "" && userPIN == "" { | ||||||
| 		return nil, false, nil | 		return nil, false, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -51,10 +52,10 @@ func pkcs11Signer(root *Root, policy *config.Signing) (signer.Signer, bool, erro | ||||||
| 		return nil, true, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) | 		return nil, true, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	conf := pkcs11.Config{ | 	conf := pkcs11key.Config{ | ||||||
| 		Module:          module, | 		Module:          module, | ||||||
| 		Token:  token, | 		TokenLabel:      tokenLabel, | ||||||
| 		Label:  label, | 		PrivateKeyLabel: privateKeyLabel, | ||||||
| 		PIN:             userPIN, | 		PIN:             userPIN, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								Makefile
								
								
								
								
							|  | @ -75,4 +75,4 @@ rpm: | ||||||
| 		test/boulder-config.json sa/_db ca/_db $(foreach var,$(OBJECTS), $(OBJDIR)/$(var)) | 		test/boulder-config.json sa/_db ca/_db $(foreach var,$(OBJECTS), $(OBJDIR)/$(var)) | ||||||
| 
 | 
 | ||||||
| bin/pkcs11bench: pre | bin/pkcs11bench: pre | ||||||
| 	go test -o ./bin/pkcs11bench -c ./test/pkcs11bench/ | 	go test -o ./bin/pkcs11bench -c ./Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key/ | ||||||
|  |  | ||||||
|  | @ -161,13 +161,12 @@ func loadKey(keyConfig cmd.KeyConfig) (priv crypto.Signer, err error) { | ||||||
| 	if pkcs11Config.Module == "" || | 	if pkcs11Config.Module == "" || | ||||||
| 		pkcs11Config.TokenLabel == "" || | 		pkcs11Config.TokenLabel == "" || | ||||||
| 		pkcs11Config.PIN == "" || | 		pkcs11Config.PIN == "" || | ||||||
| 		pkcs11Config.PrivateKeyLabel == "" || | 		pkcs11Config.PrivateKeyLabel == "" { | ||||||
| 		pkcs11Config.SlotID == nil { |  | ||||||
| 		err = fmt.Errorf("Missing a field in pkcs11Config %#v", pkcs11Config) | 		err = fmt.Errorf("Missing a field in pkcs11Config %#v", pkcs11Config) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	priv, err = pkcs11key.New(pkcs11Config.Module, | 	priv, err = pkcs11key.New(pkcs11Config.Module, | ||||||
| 		pkcs11Config.TokenLabel, pkcs11Config.PIN, pkcs11Config.PrivateKeyLabel, *pkcs11Config.SlotID) | 		pkcs11Config.TokenLabel, pkcs11Config.PIN, pkcs11Config.PrivateKeyLabel) | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -237,7 +237,6 @@ type KeyConfig struct { | ||||||
| type PKCS11Config struct { | type PKCS11Config struct { | ||||||
| 	Module          string | 	Module          string | ||||||
| 	TokenLabel      string | 	TokenLabel      string | ||||||
| 	SlotID          *int |  | ||||||
| 	PIN             string | 	PIN             string | ||||||
| 	PrivateKeyLabel string | 	PrivateKeyLabel string | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -26,7 +26,6 @@ type PKCS11Config struct { | ||||||
| 	TokenLabel      string | 	TokenLabel      string | ||||||
| 	PrivateKeyLabel string | 	PrivateKeyLabel string | ||||||
| 	PIN             string | 	PIN             string | ||||||
| 	SlotID          float64 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func readFiles(c *cli.Context) (issuer, responder, target *x509.Certificate, template ocsp.Response, pkcs11 PKCS11Config, err error) { | func readFiles(c *cli.Context) (issuer, responder, target *x509.Certificate, template ocsp.Response, pkcs11 PKCS11Config, err error) { | ||||||
|  | @ -159,7 +158,7 @@ func main() { | ||||||
| 		cmd.FailOnError(err, "Failed to read files") | 		cmd.FailOnError(err, "Failed to read files") | ||||||
| 
 | 
 | ||||||
| 		// Instantiate the private key from PKCS11
 | 		// Instantiate the private key from PKCS11
 | ||||||
| 		priv, err := pkcs11key.New(pkcs11.Module, pkcs11.TokenLabel, pkcs11.PIN, pkcs11.PrivateKeyLabel, int(pkcs11.SlotID)) | 		priv, err := pkcs11key.New(pkcs11.Module, pkcs11.TokenLabel, pkcs11.PIN, pkcs11.PrivateKeyLabel) | ||||||
| 		cmd.FailOnError(err, "Failed to load PKCS#11 key") | 		cmd.FailOnError(err, "Failed to load PKCS#11 key") | ||||||
| 
 | 
 | ||||||
| 		// Populate the remaining fields in the template
 | 		// Populate the remaining fields in the template
 | ||||||
|  |  | ||||||
|  | @ -56,14 +56,12 @@ func main() { | ||||||
| 		TokenLabel      string | 		TokenLabel      string | ||||||
| 		PIN             string | 		PIN             string | ||||||
| 		PrivateKeyLabel string | 		PrivateKeyLabel string | ||||||
| 		SlotID          float64 |  | ||||||
| 	} | 	} | ||||||
| 	pkcs11Bytes, err := ioutil.ReadFile(pkcs11FileName) | 	pkcs11Bytes, err := ioutil.ReadFile(pkcs11FileName) | ||||||
| 	panicOnError(err) | 	panicOnError(err) | ||||||
| 	err = json.Unmarshal(pkcs11Bytes, &pkcs11) | 	err = json.Unmarshal(pkcs11Bytes, &pkcs11) | ||||||
| 	panicOnError(err) | 	panicOnError(err) | ||||||
| 	slotID := int(pkcs11.SlotID) | 	p11key, err := pkcs11key.New(pkcs11.Module, pkcs11.TokenLabel, pkcs11.PIN, pkcs11.PrivateKeyLabel) | ||||||
| 	p11key, err := pkcs11key.New(pkcs11.Module, pkcs11.TokenLabel, pkcs11.PIN, pkcs11.PrivateKeyLabel, slotID) |  | ||||||
| 	panicOnError(err) | 	panicOnError(err) | ||||||
| 
 | 
 | ||||||
| 	// All of the certificates start and end at the same time
 | 	// All of the certificates start and end at the same time
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| { | { | ||||||
|   "Module": "/usr/local/Cellar/opensc/0.14.0_1/lib/opensc-pkcs11.so", |   "Module": "/usr/local/Cellar/opensc/0.14.0_1/lib/opensc-pkcs11.so", | ||||||
|   "TokenLabel": "PIV_II (PIV Card Holder pin)", |   "TokenLabel": "PIV_II (PIV Card Holder pin)", | ||||||
|   "SlotID": 1, |  | ||||||
|   "PrivateKeyLabel": "SIGN key", |   "PrivateKeyLabel": "SIGN key", | ||||||
|   "PIN": "163246" |   "PIN": "163246" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,71 +0,0 @@ | ||||||
| package pkcs11bench |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"crypto/rand" |  | ||||||
| 	"crypto/rsa" |  | ||||||
| 	"crypto/x509" |  | ||||||
| 	"flag" |  | ||||||
| 	"math/big" |  | ||||||
| 	"testing" |  | ||||||
| 	"time" |  | ||||||
| 
 |  | ||||||
| 	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/crypto/pkcs11key" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| var module = flag.String("module", "", "Path to PKCS11 module") |  | ||||||
| var tokenLabel = flag.String("tokenLabel", "", "Token label") |  | ||||||
| var pin = flag.String("pin", "", "PIN") |  | ||||||
| var privateKeyLabel = flag.String("privateKeyLabel", "", "Private key label") |  | ||||||
| var slotID = flag.Int("slotID", -1, "Slot") |  | ||||||
| 
 |  | ||||||
| // BenchmarkPKCS11 signs a certificate repeatedly using a PKCS11 token and
 |  | ||||||
| // measures speed. To run:
 |  | ||||||
| // go test -bench=. -benchtime 1m ./test/pkcs11bench/ \
 |  | ||||||
| //   -module /usr/lib/softhsm/libsofthsm.so -token-label "softhsm token" \
 |  | ||||||
| //   -pin 1234 -private-key-label "my key" -slot-id 7 -v
 |  | ||||||
| // You can adjust benchtime if you want to run for longer or shorter.
 |  | ||||||
| // TODO: Parallel benchmarking. Currently if you try this with a Yubikey Neo,
 |  | ||||||
| // you will get a bunch of CKR_USER_ALREADY_LOGGED_IN errors. This is because
 |  | ||||||
| // pkcs11key logs into the token before each signing operation (which is probably a
 |  | ||||||
| // performance bug). Also note that some PKCS11 modules (opensc) are not
 |  | ||||||
| // threadsafe.
 |  | ||||||
| func BenchmarkPKCS11(b *testing.B) { |  | ||||||
| 	if *module == "" || *tokenLabel == "" || *pin == "" || *privateKeyLabel == "" || *slotID == -1 { |  | ||||||
| 		b.Fatal("Must pass all flags: module, tokenLabel, pin, privateKeyLabel, and slotID") |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	// NOTE: To run this test, you will need to edit the following values to match
 |  | ||||||
| 	// your PKCS11 token.
 |  | ||||||
| 	p, err := pkcs11key.New(*module, *tokenLabel, *pin, *privateKeyLabel, *slotID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		b.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	defer p.Destroy() |  | ||||||
| 
 |  | ||||||
| 	N := big.NewInt(1) |  | ||||||
| 	N.Lsh(N, 6000) |  | ||||||
| 	// A minimal, bogus certificate to be signed.
 |  | ||||||
| 	template := x509.Certificate{ |  | ||||||
| 		SerialNumber:       big.NewInt(1), |  | ||||||
| 		PublicKeyAlgorithm: x509.RSA, |  | ||||||
| 		NotBefore:          time.Now(), |  | ||||||
| 		NotAfter:           time.Now(), |  | ||||||
| 
 |  | ||||||
| 		PublicKey: &rsa.PublicKey{ |  | ||||||
| 			N: N, |  | ||||||
| 			E: 1 << 17, |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Reset the benchmarking timer so we don't include setup time.
 |  | ||||||
| 	b.ResetTimer() |  | ||||||
| 
 |  | ||||||
| 	for i := 0; i < b.N; i++ { |  | ||||||
| 		_, err = x509.CreateCertificate(rand.Reader, &template, &template, template.PublicKey, p) |  | ||||||
| 		if err != nil { |  | ||||||
| 			b.Fatal(err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue