key.go 14.3 KB
Newer Older
1
// Copyright (C) 2017. See AUTHORS.
JT Olds's avatar
JT Olds committed
2 3 4 5 6 7 8 9 10 11 12 13 14
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

JT Olds's avatar
JT Olds committed
15 16
package openssl

Andrew Harding's avatar
Andrew Harding committed
17
// #include "shim.h"
JT Olds's avatar
JT Olds committed
18 19 20
import "C"

import (
21 22 23 24
	"errors"
	"io/ioutil"
	"runtime"
	"unsafe"
JT Olds's avatar
JT Olds committed
25 26
)

27 28 29 30
var ( // some (effectively) constants for tests to refer to
	ed25519_support = C.X_ED25519_SUPPORT != 0
)

31 32 33
type Method *C.EVP_MD

var (
Andrew Harding's avatar
Andrew Harding committed
34 35 36
	SHA1_Method   Method = C.X_EVP_sha1()
	SHA256_Method Method = C.X_EVP_sha256()
	SHA512_Method Method = C.X_EVP_sha512()
37 38
)

39 40
// Constants for the various key types.
// Mapping of name -> NID taken from openssl/evp.h
41
const (
42 43 44 45 46 47 48 49 50 51
	KeyTypeNone    = NID_undef
	KeyTypeRSA     = NID_rsaEncryption
	KeyTypeRSA2    = NID_rsa
	KeyTypeDSA     = NID_dsa
	KeyTypeDSA1    = NID_dsa_2
	KeyTypeDSA2    = NID_dsaWithSHA
	KeyTypeDSA3    = NID_dsaWithSHA1
	KeyTypeDSA4    = NID_dsaWithSHA1_2
	KeyTypeDH      = NID_dhKeyAgreement
	KeyTypeDHX     = NID_dhpublicnumber
52
	KeyTypeEC      = NID_X9_62_id_ecPublicKey
53 54 55
	KeyTypeHMAC    = NID_hmac
	KeyTypeCMAC    = NID_cmac
	KeyTypeTLS1PRF = NID_tls1_prf
56
	KeyTypeHKDF    = NID_hkdf
parasssh's avatar
parasssh committed
57 58 59 60
	KeyTypeX25519  = NID_X25519
	KeyTypeX448    = NID_X448
	KeyTypeED25519 = NID_ED25519
	KeyTypeED448   = NID_ED448
61 62
)

JT Olds's avatar
JT Olds committed
63
type PublicKey interface {
64 65 66
	// Verifies the data signature using PKCS1.15
	VerifyPKCS1v15(method Method, data, sig []byte) error

67 68 69
	// MarshalPKIXPublicKeyPEM converts the public key to PEM-encoded PKIX
	// format
	MarshalPKIXPublicKeyPEM() (pem_block []byte, err error)
JT Olds's avatar
JT Olds committed
70

71 72 73
	// MarshalPKIXPublicKeyDER converts the public key to DER-encoded PKIX
	// format
	MarshalPKIXPublicKeyDER() (der_block []byte, err error)
JT Olds's avatar
JT Olds committed
74

75
	// KeyType returns an identifier for what kind of key is represented by this
76
	// object.
77
	KeyType() NID
78 79 80 81 82 83

	// BaseType returns an identifier for what kind of key is represented
	// by this object.
	// Keys that share same algorithm but use different legacy formats
	// will have the same BaseType.
	//
84 85
	// For example, a key with a `KeyType() == KeyTypeRSA` and a key with a
	// `KeyType() == KeyTypeRSA2` would both have `BaseType() == KeyTypeRSA`.
86
	BaseType() NID
87

88 89 90
	// Equal compares the key with the passed in key.
	Equal(key PublicKey) bool

91 92 93
	// Size returns the size (in bytes) of signatures created with this key.
	Size() int

94
	evpPKey() *C.EVP_PKEY
JT Olds's avatar
JT Olds committed
95 96 97
}

type PrivateKey interface {
98
	PublicKey
JT Olds's avatar
JT Olds committed
99

100 101 102
	// Signs the data using PKCS1.15
	SignPKCS1v15(Method, []byte) ([]byte, error)

103 104 105
	// MarshalPKCS1PrivateKeyPEM converts the private key to PEM-encoded PKCS1
	// format
	MarshalPKCS1PrivateKeyPEM() (pem_block []byte, err error)
JT Olds's avatar
JT Olds committed
106

107 108 109
	// MarshalPKCS1PrivateKeyDER converts the private key to DER-encoded PKCS1
	// format
	MarshalPKCS1PrivateKeyDER() (der_block []byte, err error)
JT Olds's avatar
JT Olds committed
110 111 112
}

type pKey struct {
113
	key *C.EVP_PKEY
JT Olds's avatar
JT Olds committed
114 115 116 117
}

func (key *pKey) evpPKey() *C.EVP_PKEY { return key.key }

118 119 120 121
func (key *pKey) Equal(other PublicKey) bool {
	return C.EVP_PKEY_cmp(key.key, other.evpPKey()) == 1
}

122 123
func (key *pKey) KeyType() NID {
	return NID(C.EVP_PKEY_id(key.key))
124 125
}

126 127 128 129
func (key *pKey) Size() int {
	return int(C.EVP_PKEY_size(key.key))
}

130 131
func (key *pKey) BaseType() NID {
	return NID(C.EVP_PKEY_base_id(key.key))
132 133
}

134
func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) {
parasssh's avatar
parasssh committed
135

Andrew Harding's avatar
Andrew Harding committed
136 137
	ctx := C.X_EVP_MD_CTX_new()
	defer C.X_EVP_MD_CTX_free(ctx)
138

parasssh's avatar
parasssh committed
139 140 141 142 143
	if key.KeyType() == KeyTypeED25519 {
		// do ED specific one-shot sign

		if method != nil || len(data) == 0 {
			return nil, errors.New("signpkcs1v15: 0-length data or non-null digest")
144
		}
parasssh's avatar
parasssh committed
145 146 147 148 149 150 151

		if 1 != C.X_EVP_DigestSignInit(ctx, nil, nil, nil, key.key) {
			return nil, errors.New("signpkcs1v15: failed to init signature")
		}

		// evp signatures are 64 bytes
		sig := make([]byte, 64, 64)
152
		var sigblen C.size_t = 64
parasssh's avatar
parasssh committed
153
		if 1 != C.X_EVP_DigestSign(ctx,
154 155 156
			((*C.uchar)(unsafe.Pointer(&sig[0]))),
			&sigblen,
			(*C.uchar)(unsafe.Pointer(&data[0])),
157
			C.size_t(len(data))) {
parasssh's avatar
parasssh committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
			return nil, errors.New("signpkcs1v15: failed to do one-shot signature")
		}

		return sig[:sigblen], nil
	} else {
		if 1 != C.X_EVP_SignInit(ctx, method) {
			return nil, errors.New("signpkcs1v15: failed to init signature")
		}
		if len(data) > 0 {
			if 1 != C.X_EVP_SignUpdate(
				ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
				return nil, errors.New("signpkcs1v15: failed to update signature")
			}
		}
		sig := make([]byte, C.X_EVP_PKEY_size(key.key))
		var sigblen C.uint
		if 1 != C.X_EVP_SignFinal(ctx,
			((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) {
			return nil, errors.New("signpkcs1v15: failed to finalize signature")
		}
		return sig[:sigblen], nil
179 180 181 182
	}
}

func (key *pKey) VerifyPKCS1v15(method Method, data, sig []byte) error {
Andrew Harding's avatar
Andrew Harding committed
183 184
	ctx := C.X_EVP_MD_CTX_new()
	defer C.X_EVP_MD_CTX_free(ctx)
185

186 187 188 189
	if len(sig) == 0 {
		return errors.New("verifypkcs1v15: 0-length sig")
	}

parasssh's avatar
parasssh committed
190 191 192
	if key.KeyType() == KeyTypeED25519 {
		// do ED specific one-shot sign

193 194
		if method != nil || len(data) == 0 {
			return errors.New("verifypkcs1v15: 0-length data or non-null digest")
195
		}
parasssh's avatar
parasssh committed
196 197 198 199 200 201

		if 1 != C.X_EVP_DigestVerifyInit(ctx, nil, nil, nil, key.key) {
			return errors.New("verifypkcs1v15: failed to init verify")
		}

		if 1 != C.X_EVP_DigestVerify(ctx,
202
			((*C.uchar)(unsafe.Pointer(&sig[0]))),
203
			C.size_t(len(sig)),
204
			(*C.uchar)(unsafe.Pointer(&data[0])),
205
			C.size_t(len(data))) {
parasssh's avatar
parasssh committed
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
			return errors.New("verifypkcs1v15: failed to do one-shot verify")
		}

		return nil

	} else {
		if 1 != C.X_EVP_VerifyInit(ctx, method) {
			return errors.New("verifypkcs1v15: failed to init verify")
		}
		if len(data) > 0 {
			if 1 != C.X_EVP_VerifyUpdate(
				ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
				return errors.New("verifypkcs1v15: failed to update verify")
			}
		}
		if 1 != C.X_EVP_VerifyFinal(ctx,
			((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) {
			return errors.New("verifypkcs1v15: failed to finalize verify")
		}
		return nil
226 227 228
	}
}

JT Olds's avatar
JT Olds committed
229
func (key *pKey) MarshalPKCS1PrivateKeyPEM() (pem_block []byte,
230 231 232 233 234 235
	err error) {
	bio := C.BIO_new(C.BIO_s_mem())
	if bio == nil {
		return nil, errors.New("failed to allocate memory BIO")
	}
	defer C.BIO_free(bio)
236 237 238 239

	// PEM_write_bio_PrivateKey_traditional will use the key-specific PKCS1
	// format if one is available for that key type, otherwise it will encode
	// to a PKCS8 key.
240
	if int(C.X_PEM_write_bio_PrivateKey_traditional(bio, key.key, nil, nil,
241
		C.int(0), nil, nil)) != 1 {
242 243
		return nil, errors.New("failed dumping private key")
	}
244

245
	return ioutil.ReadAll(asAnyBio(bio))
JT Olds's avatar
JT Olds committed
246 247 248
}

func (key *pKey) MarshalPKCS1PrivateKeyDER() (der_block []byte,
249 250 251 252 253 254
	err error) {
	bio := C.BIO_new(C.BIO_s_mem())
	if bio == nil {
		return nil, errors.New("failed to allocate memory BIO")
	}
	defer C.BIO_free(bio)
255 256

	if int(C.i2d_PrivateKey_bio(bio, key.key)) != 1 {
257 258
		return nil, errors.New("failed dumping private key der")
	}
259

260
	return ioutil.ReadAll(asAnyBio(bio))
JT Olds's avatar
JT Olds committed
261 262
}

JT Olds's avatar
JT Olds committed
263
func (key *pKey) MarshalPKIXPublicKeyPEM() (pem_block []byte,
264 265 266 267 268 269
	err error) {
	bio := C.BIO_new(C.BIO_s_mem())
	if bio == nil {
		return nil, errors.New("failed to allocate memory BIO")
	}
	defer C.BIO_free(bio)
270

271
	if int(C.PEM_write_bio_PUBKEY(bio, key.key)) != 1 {
272 273
		return nil, errors.New("failed dumping public key pem")
	}
274

275
	return ioutil.ReadAll(asAnyBio(bio))
JT Olds's avatar
JT Olds committed
276 277
}

JT Olds's avatar
JT Olds committed
278
func (key *pKey) MarshalPKIXPublicKeyDER() (der_block []byte,
279 280 281 282 283 284
	err error) {
	bio := C.BIO_new(C.BIO_s_mem())
	if bio == nil {
		return nil, errors.New("failed to allocate memory BIO")
	}
	defer C.BIO_free(bio)
285 286

	if int(C.i2d_PUBKEY_bio(bio, key.key)) != 1 {
287 288
		return nil, errors.New("failed dumping public key der")
	}
289

290
	return ioutil.ReadAll(asAnyBio(bio))
JT Olds's avatar
JT Olds committed
291 292
}

JT Olds's avatar
JT Olds committed
293 294
// LoadPrivateKeyFromPEM loads a private key from a PEM-encoded block.
func LoadPrivateKeyFromPEM(pem_block []byte) (PrivateKey, error) {
JT Olds's avatar
JT Olds committed
295 296 297
	if len(pem_block) == 0 {
		return nil, errors.New("empty pem block")
	}
298 299 300 301 302 303 304
	bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]),
		C.int(len(pem_block)))
	if bio == nil {
		return nil, errors.New("failed creating bio")
	}
	defer C.BIO_free(bio)

305
	key := C.PEM_read_bio_PrivateKey(bio, nil, nil, nil)
306
	if key == nil {
307
		return nil, errors.New("failed reading private key")
308 309 310 311
	}

	p := &pKey{key: key}
	runtime.SetFinalizer(p, func(p *pKey) {
Andrew Harding's avatar
Andrew Harding committed
312
		C.X_EVP_PKEY_free(p.key)
313 314 315 316
	})
	return p, nil
}

317 318
// LoadPrivateKeyFromPEMWithPassword loads a private key from a PEM-encoded block.
func LoadPrivateKeyFromPEMWithPassword(pem_block []byte, password string) (
JT Olds's avatar
JT Olds committed
319
	PrivateKey, error) {
320 321 322 323 324 325 326 327 328 329
	if len(pem_block) == 0 {
		return nil, errors.New("empty pem block")
	}
	bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]),
		C.int(len(pem_block)))
	if bio == nil {
		return nil, errors.New("failed creating bio")
	}
	defer C.BIO_free(bio)
	cs := C.CString(password)
JT Olds's avatar
JT Olds committed
330
	defer C.free(unsafe.Pointer(cs))
331
	key := C.PEM_read_bio_PrivateKey(bio, nil, nil, unsafe.Pointer(cs))
332
	if key == nil {
333
		return nil, errors.New("failed reading private key")
334 335 336 337
	}

	p := &pKey{key: key}
	runtime.SetFinalizer(p, func(p *pKey) {
Andrew Harding's avatar
Andrew Harding committed
338
		C.X_EVP_PKEY_free(p.key)
339 340 341 342
	})
	return p, nil
}

Colin Misare's avatar
Colin Misare committed
343 344 345 346 347 348 349 350 351 352 353 354
// LoadPrivateKeyFromDER loads a private key from a DER-encoded block.
func LoadPrivateKeyFromDER(der_block []byte) (PrivateKey, error) {
	if len(der_block) == 0 {
		return nil, errors.New("empty der block")
	}
	bio := C.BIO_new_mem_buf(unsafe.Pointer(&der_block[0]),
		C.int(len(der_block)))
	if bio == nil {
		return nil, errors.New("failed creating bio")
	}
	defer C.BIO_free(bio)

355
	key := C.d2i_PrivateKey_bio(bio, nil)
Colin Misare's avatar
Colin Misare committed
356
	if key == nil {
357
		return nil, errors.New("failed reading private key der")
Colin Misare's avatar
Colin Misare committed
358 359 360 361
	}

	p := &pKey{key: key}
	runtime.SetFinalizer(p, func(p *pKey) {
Andrew Harding's avatar
Andrew Harding committed
362
		C.X_EVP_PKEY_free(p.key)
Colin Misare's avatar
Colin Misare committed
363 364 365 366
	})
	return p, nil
}

367 368 369 370 371 372 373
// LoadPrivateKeyFromPEMWidthPassword loads a private key from a PEM-encoded block.
// Backwards-compatible with typo
func LoadPrivateKeyFromPEMWidthPassword(pem_block []byte, password string) (
	PrivateKey, error) {
	return LoadPrivateKeyFromPEMWithPassword(pem_block, password)
}

JT Olds's avatar
JT Olds committed
374 375
// LoadPublicKeyFromPEM loads a public key from a PEM-encoded block.
func LoadPublicKeyFromPEM(pem_block []byte) (PublicKey, error) {
376 377 378 379 380 381 382 383 384 385
	if len(pem_block) == 0 {
		return nil, errors.New("empty pem block")
	}
	bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]),
		C.int(len(pem_block)))
	if bio == nil {
		return nil, errors.New("failed creating bio")
	}
	defer C.BIO_free(bio)

386
	key := C.PEM_read_bio_PUBKEY(bio, nil, nil, nil)
JT Olds's avatar
JT Olds committed
387
	if key == nil {
388
		return nil, errors.New("failed reading public key der")
JT Olds's avatar
JT Olds committed
389 390 391 392
	}

	p := &pKey{key: key}
	runtime.SetFinalizer(p, func(p *pKey) {
Andrew Harding's avatar
Andrew Harding committed
393
		C.X_EVP_PKEY_free(p.key)
JT Olds's avatar
JT Olds committed
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	})
	return p, nil
}

// LoadPublicKeyFromDER loads a public key from a DER-encoded block.
func LoadPublicKeyFromDER(der_block []byte) (PublicKey, error) {
	if len(der_block) == 0 {
		return nil, errors.New("empty der block")
	}
	bio := C.BIO_new_mem_buf(unsafe.Pointer(&der_block[0]),
		C.int(len(der_block)))
	if bio == nil {
		return nil, errors.New("failed creating bio")
	}
	defer C.BIO_free(bio)

410
	key := C.d2i_PUBKEY_bio(bio, nil)
411
	if key == nil {
412
		return nil, errors.New("failed reading public key der")
413 414 415 416
	}

	p := &pKey{key: key}
	runtime.SetFinalizer(p, func(p *pKey) {
Andrew Harding's avatar
Andrew Harding committed
417
		C.X_EVP_PKEY_free(p.key)
418 419
	})
	return p, nil
JT Olds's avatar
JT Olds committed
420 421
}

422 423
// GenerateRSAKey generates a new RSA private key with an exponent of 3.
func GenerateRSAKey(bits int) (PrivateKey, error) {
424 425 426 427 428
	return GenerateRSAKeyWithExponent(bits, 3)
}

// GenerateRSAKeyWithExponent generates a new RSA private key.
func GenerateRSAKeyWithExponent(bits int, exponent int) (PrivateKey, error) {
429 430 431
	rsa := C.RSA_generate_key(C.int(bits), C.ulong(exponent), nil, nil)
	if rsa == nil {
		return nil, errors.New("failed to generate RSA key")
432
	}
Andrew Harding's avatar
Andrew Harding committed
433
	key := C.X_EVP_PKEY_new()
434 435
	if key == nil {
		return nil, errors.New("failed to allocate EVP_PKEY")
436
	}
Andrew Harding's avatar
Andrew Harding committed
437 438
	if C.X_EVP_PKEY_assign_charp(key, C.EVP_PKEY_RSA, (*C.char)(unsafe.Pointer(rsa))) != 1 {
		C.X_EVP_PKEY_free(key)
439
		return nil, errors.New("failed to assign RSA key")
440
	}
441 442
	p := &pKey{key: key}
	runtime.SetFinalizer(p, func(p *pKey) {
Andrew Harding's avatar
Andrew Harding committed
443
		C.X_EVP_PKEY_free(p.key)
444
	})
445
	return p, nil
JT Olds's avatar
JT Olds committed
446
}
Christopher Dudley's avatar
Christopher Dudley committed
447 448 449 450 451 452 453 454 455 456 457 458 459

// GenerateECKey generates a new elliptic curve private key on the speicified
// curve.
func GenerateECKey(curve EllipticCurve) (PrivateKey, error) {

	// Create context for parameter generation
	paramCtx := C.EVP_PKEY_CTX_new_id(C.EVP_PKEY_EC, nil)
	if paramCtx == nil {
		return nil, errors.New("failed creating EC parameter generation context")
	}
	defer C.EVP_PKEY_CTX_free(paramCtx)

	// Intialize the parameter generation
460
	if int(C.EVP_PKEY_paramgen_init(paramCtx)) != 1 {
Christopher Dudley's avatar
Christopher Dudley committed
461 462 463 464
		return nil, errors.New("failed initializing EC parameter generation context")
	}

	// Set curve in EC parameter generation context
465
	if int(C.X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(paramCtx, C.int(curve))) != 1 {
Christopher Dudley's avatar
Christopher Dudley committed
466 467 468 469 470
		return nil, errors.New("failed setting curve in EC parameter generation context")
	}

	// Create parameter object
	var params *C.EVP_PKEY
471
	if int(C.EVP_PKEY_paramgen(paramCtx, &params)) != 1 {
Christopher Dudley's avatar
Christopher Dudley committed
472 473 474 475 476 477 478 479 480 481 482 483 484
		return nil, errors.New("failed creating EC key generation parameters")
	}
	defer C.EVP_PKEY_free(params)

	// Create context for the key generation
	keyCtx := C.EVP_PKEY_CTX_new(params, nil)
	if keyCtx == nil {
		return nil, errors.New("failed creating EC key generation context")
	}
	defer C.EVP_PKEY_CTX_free(keyCtx)

	// Generate the key
	var privKey *C.EVP_PKEY
485
	if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 {
Christopher Dudley's avatar
Christopher Dudley committed
486 487
		return nil, errors.New("failed initializing EC key generation context")
	}
488
	if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 {
Christopher Dudley's avatar
Christopher Dudley committed
489 490 491 492 493 494 495 496 497
		return nil, errors.New("failed generating EC private key")
	}

	p := &pKey{key: privKey}
	runtime.SetFinalizer(p, func(p *pKey) {
		C.X_EVP_PKEY_free(p.key)
	})
	return p, nil
}
parasssh's avatar
parasssh committed
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522

// GenerateED25519Key generates a Ed25519 key
func GenerateED25519Key() (PrivateKey, error) {
	// Key context
	keyCtx := C.EVP_PKEY_CTX_new_id(C.X_EVP_PKEY_ED25519, nil)
	if keyCtx == nil {
		return nil, errors.New("failed creating EC parameter generation context")
	}
	defer C.EVP_PKEY_CTX_free(keyCtx)

	// Generate the key
	var privKey *C.EVP_PKEY
	if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 {
		return nil, errors.New("failed initializing ED25519 key generation context")
	}
	if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 {
		return nil, errors.New("failed generating ED25519 private key")
	}

	p := &pKey{key: privKey}
	runtime.SetFinalizer(p, func(p *pKey) {
		C.X_EVP_PKEY_free(p.key)
	})
	return p, nil
}