|
14 | 14 |
|
15 | 15 | package openssl
|
16 | 16 |
|
| 17 | +// #include "openssl/engine.h" |
17 | 18 | // #include "shim.h"
|
18 | 19 | import "C"
|
19 | 20 |
|
@@ -105,6 +106,7 @@ type PrivateKey interface {
|
105 | 106 |
|
106 | 107 | type pKey struct {
|
107 | 108 | key *C.EVP_PKEY
|
| 109 | + engine_ref interface{} //see comment below in EngineLoadPrivateKey |
108 | 110 | }
|
109 | 111 |
|
110 | 112 | func (key *pKey) evpPKey() *C.EVP_PKEY { return key.key }
|
@@ -272,6 +274,31 @@ func (key *pKey) MarshalPKIXPublicKeyDER() (der_block []byte,
|
272 | 274 | return ioutil.ReadAll(asAnyBio(bio))
|
273 | 275 | }
|
274 | 276 |
|
| 277 | +// EngineLoadPrivateKey loads a private key by id |
| 278 | +// the id is a pkcs#11 URI https://tools.ietf.org/html/rfc7512#section-2.3 |
| 279 | +// Engine comes from e.g.: e,err:=openssl.EngineById("pkcs11") |
| 280 | +func EngineLoadPrivateKey(e *Engine, id string) (PrivateKey, error) { |
| 281 | + if e == nil { |
| 282 | + return nil, errors.New("ENGINE_load_private_key cannot be called with NULL engine") |
| 283 | + } |
| 284 | + |
| 285 | + keyID := C.CString(id) |
| 286 | + defer C.free(unsafe.Pointer(keyID)) |
| 287 | + |
| 288 | + key := C.ENGINE_load_private_key(e.e, keyID, nil, nil) |
| 289 | + if key == nil { |
| 290 | + return nil, errors.New("cannot load private key, ENGINE_load_private_key error") |
| 291 | + } |
| 292 | + |
| 293 | + // engine_ref trick inspired by the work of Renato Aguiar https://github.com/renatoaguiar |
| 294 | + // it prevents the engine to be freed while we still use the key. |
| 295 | + p := &pKey{key: key, engine_ref: e} |
| 296 | + runtime.SetFinalizer(p, func(p *pKey) { |
| 297 | + C.X_EVP_PKEY_free(p.key) |
| 298 | + }) |
| 299 | + return p, nil |
| 300 | +} |
| 301 | + |
275 | 302 | // LoadPrivateKeyFromPEM loads a private key from a PEM-encoded block.
|
276 | 303 | func LoadPrivateKeyFromPEM(pem_block []byte) (PrivateKey, error) {
|
277 | 304 | if len(pem_block) == 0 {
|
|
0 commit comments