mirror of
https://github.com/libp2p/go-openssl.git
synced 2024-12-27 23:40:18 +08:00
Merge pull request #18 from lunixbochs/keygen
restructure certs/keys; add key/cert generation
This commit is contained in:
commit
a6e28b4958
367
cert.go
Normal file
367
cert.go
Normal file
@ -0,0 +1,367 @@
|
||||
// Copyright (C) 2014 Space Monkey, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build cgo
|
||||
|
||||
package openssl
|
||||
|
||||
// #include <openssl/conf.h>
|
||||
// #include <openssl/ssl.h>
|
||||
// #include <openssl/x509v3.h>
|
||||
//
|
||||
// void OPENSSL_free_not_a_macro(void *ref) { OPENSSL_free(ref); }
|
||||
//
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type EVP_MD int
|
||||
|
||||
const (
|
||||
EVP_NULL EVP_MD = iota
|
||||
EVP_MD5 EVP_MD = iota
|
||||
EVP_SHA EVP_MD = iota
|
||||
EVP_SHA1 EVP_MD = iota
|
||||
EVP_DSS EVP_MD = iota
|
||||
EVP_DSS1 EVP_MD = iota
|
||||
EVP_MDC2 EVP_MD = iota
|
||||
EVP_RIPEMD160 EVP_MD = iota
|
||||
EVP_SHA224 EVP_MD = iota
|
||||
EVP_SHA256 EVP_MD = iota
|
||||
EVP_SHA384 EVP_MD = iota
|
||||
EVP_SHA512 EVP_MD = iota
|
||||
)
|
||||
|
||||
type Certificate struct {
|
||||
x *C.X509
|
||||
Issuer *Certificate
|
||||
ref interface{}
|
||||
pubKey PublicKey
|
||||
}
|
||||
|
||||
type CertificateInfo struct {
|
||||
Serial int
|
||||
Issued time.Duration
|
||||
Expires time.Duration
|
||||
Country string
|
||||
Organization string
|
||||
CommonName string
|
||||
}
|
||||
|
||||
type Name struct {
|
||||
name *C.X509_NAME
|
||||
}
|
||||
|
||||
// Allocate and return a new Name object.
|
||||
func NewName() (*Name, error) {
|
||||
n := C.X509_NAME_new()
|
||||
if n == nil {
|
||||
return nil, errors.New("could not create x509 name")
|
||||
}
|
||||
name := &Name{name: n}
|
||||
runtime.SetFinalizer(name, func(n *Name) {
|
||||
C.X509_NAME_free(n.name)
|
||||
})
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// AddTextEntry appends a text entry to an X509 NAME.
|
||||
func (n *Name) AddTextEntry(field, value string) error {
|
||||
cfield := C.CString(field)
|
||||
defer C.free(unsafe.Pointer(cfield))
|
||||
cvalue := (*C.uchar)(unsafe.Pointer(C.CString(value)))
|
||||
defer C.free(unsafe.Pointer(cvalue))
|
||||
ret := C.X509_NAME_add_entry_by_txt(
|
||||
n.name, cfield, C.MBSTRING_ASC, cvalue, -1, -1, 0)
|
||||
if ret != 1 {
|
||||
return errors.New("failed to add x509 name text entry")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddTextEntries allows adding multiple entries to a name in one call.
|
||||
func (n *Name) AddTextEntries(entries map[string]string) error {
|
||||
for f, v := range entries {
|
||||
if err := n.AddTextEntry(f, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewCertificate generates a basic certificate based
|
||||
// on the provided CertificateInfo struct
|
||||
func NewCertificate(info *CertificateInfo, key PublicKey) (*Certificate, error) {
|
||||
c := &Certificate{x: C.X509_new()}
|
||||
runtime.SetFinalizer(c, func(c *Certificate) {
|
||||
C.X509_free(c.x)
|
||||
})
|
||||
|
||||
name, err := c.GetSubjectName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = name.AddTextEntries(map[string]string{
|
||||
"C": info.Country,
|
||||
"O": info.Organization,
|
||||
"CN": info.CommonName,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// self-issue for now
|
||||
if err := c.SetIssuerName(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.SetSerial(info.Serial); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.SetIssueDate(info.Issued); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.SetExpireDate(info.Expires); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.SetPubKey(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Certificate) GetSubjectName() (*Name, error) {
|
||||
n := C.X509_get_subject_name(c.x)
|
||||
if n == nil {
|
||||
return nil, errors.New("failed to get subject name")
|
||||
}
|
||||
return &Name{name: n}, nil
|
||||
}
|
||||
|
||||
func (c *Certificate) GetIssuerName() (*Name, error) {
|
||||
n := C.X509_get_issuer_name(c.x)
|
||||
if n == nil {
|
||||
return nil, errors.New("failed to get issuer name")
|
||||
}
|
||||
return &Name{name: n}, nil
|
||||
}
|
||||
|
||||
func (c *Certificate) SetSubjectName(name *Name) error {
|
||||
if C.X509_set_subject_name(c.x, name.name) != 1 {
|
||||
return errors.New("failed to set subject name")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetIssuer updates the stored Issuer cert
|
||||
// and the internal x509 Issuer Name of a certificate.
|
||||
// The stored Issuer reference is used when adding extensions.
|
||||
func (c *Certificate) SetIssuer(issuer *Certificate) error {
|
||||
name, err := issuer.GetSubjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = c.SetIssuerName(name); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Issuer = issuer
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetIssuerName populates the issuer name of a certificate.
|
||||
// Use SetIssuer instead, if possible.
|
||||
func (c *Certificate) SetIssuerName(name *Name) error {
|
||||
if C.X509_set_issuer_name(c.x, name.name) != 1 {
|
||||
return errors.New("failed to set subject name")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSerial sets the serial of a certificate.
|
||||
func (c *Certificate) SetSerial(serial int) error {
|
||||
if C.ASN1_INTEGER_set(C.X509_get_serialNumber(c.x), C.long(serial)) != 1 {
|
||||
return errors.New("failed to set serial")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetIssueDate sets the certificate issue date relative to the current time.
|
||||
func (c *Certificate) SetIssueDate(when time.Duration) error {
|
||||
offset := C.long(when / time.Second)
|
||||
result := C.X509_gmtime_adj(c.x.cert_info.validity.notBefore, offset)
|
||||
if result == nil {
|
||||
return errors.New("failed to set issue date")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetExpireDate sets the certificate issue date relative to the current time.
|
||||
func (c *Certificate) SetExpireDate(when time.Duration) error {
|
||||
offset := C.long(when / time.Second)
|
||||
result := C.X509_gmtime_adj(c.x.cert_info.validity.notAfter, offset)
|
||||
if result == nil {
|
||||
return errors.New("failed to set expire date")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPubKey assigns a new public key to a certificate.
|
||||
func (c *Certificate) SetPubKey(pubKey PublicKey) error {
|
||||
c.pubKey = pubKey
|
||||
if C.X509_set_pubkey(c.x, pubKey.evpPKey()) != 1 {
|
||||
return errors.New("failed to set public key")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sign a certificate using a private key and a digest name.
|
||||
// Accepted digest names are 'sha256', 'sha384', and 'sha512'.
|
||||
func (c *Certificate) Sign(privKey PrivateKey, digest EVP_MD) error {
|
||||
switch digest {
|
||||
case EVP_SHA256:
|
||||
case EVP_SHA384:
|
||||
case EVP_SHA512:
|
||||
default:
|
||||
return errors.New("Unsupported digest" +
|
||||
"You're probably looking for 'EVP_SHA256' or 'EVP_SHA512'.")
|
||||
}
|
||||
return c.insecureSign(privKey, digest)
|
||||
}
|
||||
|
||||
func (c *Certificate) insecureSign(privKey PrivateKey, digest EVP_MD) error {
|
||||
var md *C.EVP_MD
|
||||
switch digest {
|
||||
// please don't use these digest functions
|
||||
case EVP_NULL:
|
||||
md = C.EVP_md_null()
|
||||
case EVP_MD5:
|
||||
md = C.EVP_md5()
|
||||
case EVP_SHA:
|
||||
md = C.EVP_sha()
|
||||
case EVP_SHA1:
|
||||
md = C.EVP_sha1()
|
||||
case EVP_DSS:
|
||||
md = C.EVP_dss()
|
||||
case EVP_DSS1:
|
||||
md = C.EVP_dss1()
|
||||
case EVP_RIPEMD160:
|
||||
md = C.EVP_ripemd160()
|
||||
case EVP_SHA224:
|
||||
md = C.EVP_sha224()
|
||||
// you actually want one of these
|
||||
case EVP_SHA256:
|
||||
md = C.EVP_sha256()
|
||||
case EVP_SHA384:
|
||||
md = C.EVP_sha384()
|
||||
case EVP_SHA512:
|
||||
md = C.EVP_sha512()
|
||||
}
|
||||
if C.X509_sign(c.x, privKey.evpPKey(), md) <= 0 {
|
||||
return errors.New("failed to sign certificate")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add an extension to a certificate.
|
||||
// Extension constants are NID_* as found in openssl.
|
||||
func (c *Certificate) AddExtension(nid NID, value string) error {
|
||||
issuer := c
|
||||
if c.Issuer != nil {
|
||||
issuer = c.Issuer
|
||||
}
|
||||
var ctx C.X509V3_CTX
|
||||
C.X509V3_set_ctx(&ctx, c.x, issuer.x, nil, nil, 0)
|
||||
ex := C.X509V3_EXT_conf_nid(nil, &ctx, C.int(nid), C.CString(value))
|
||||
if ex == nil {
|
||||
return errors.New("failed to create x509v3 extension")
|
||||
}
|
||||
defer C.X509_EXTENSION_free(ex)
|
||||
if C.X509_add_ext(c.x, ex, -1) <= 0 {
|
||||
return errors.New("failed to add x509v3 extension")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wraps AddExtension using a map of NID to text extension.
|
||||
// Will return without finishing if it encounters an error.
|
||||
func (c *Certificate) AddExtensions(extensions map[NID]string) error {
|
||||
for nid, value := range extensions {
|
||||
if err := c.AddExtension(nid, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadCertificateFromPEM loads an X509 certificate from a PEM-encoded block.
|
||||
func LoadCertificateFromPEM(pem_block []byte) (*Certificate, error) {
|
||||
if len(pem_block) == 0 {
|
||||
return nil, errors.New("empty pem block")
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]),
|
||||
C.int(len(pem_block)))
|
||||
cert := C.PEM_read_bio_X509(bio, nil, nil, nil)
|
||||
C.BIO_free(bio)
|
||||
if cert == nil {
|
||||
return nil, errorFromErrorQueue()
|
||||
}
|
||||
x := &Certificate{x: cert}
|
||||
runtime.SetFinalizer(x, func(x *Certificate) {
|
||||
C.X509_free(x.x)
|
||||
})
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// MarshalPEM converts the X509 certificate to PEM-encoded format
|
||||
func (c *Certificate) MarshalPEM() (pem_block []byte, 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)
|
||||
if int(C.PEM_write_bio_X509(bio, c.x)) != 1 {
|
||||
return nil, errors.New("failed dumping certificate")
|
||||
}
|
||||
return ioutil.ReadAll(asAnyBio(bio))
|
||||
}
|
||||
|
||||
// PublicKey returns the public key embedded in the X509 certificate.
|
||||
func (c *Certificate) PublicKey() (PublicKey, error) {
|
||||
pkey := C.X509_get_pubkey(c.x)
|
||||
if pkey == nil {
|
||||
return nil, errors.New("no public key found")
|
||||
}
|
||||
key := &pKey{key: pkey}
|
||||
runtime.SetFinalizer(key, func(key *pKey) {
|
||||
C.EVP_PKEY_free(key.key)
|
||||
})
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// GetSerialNumberHex returns the certificate's serial number in hex format
|
||||
func (c *Certificate) GetSerialNumberHex() (serial string) {
|
||||
asn1_i := C.X509_get_serialNumber(c.x)
|
||||
bignum := C.ASN1_INTEGER_to_BN(asn1_i, nil)
|
||||
hex := C.BN_bn2hex(bignum)
|
||||
serial = C.GoString(hex)
|
||||
C.BN_free(bignum)
|
||||
C.OPENSSL_free_not_a_macro(unsafe.Pointer(hex))
|
||||
return
|
||||
}
|
101
cert_test.go
Normal file
101
cert_test.go
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2014 Ryan Hileman
|
||||
//
|
||||
// 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.
|
||||
|
||||
package openssl
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCertGenerate(t *testing.T) {
|
||||
key, err := GenerateRSAKey(2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
info := &CertificateInfo{
|
||||
Serial: 1,
|
||||
Issued: 0,
|
||||
Expires: 24 * time.Hour,
|
||||
Country: "US",
|
||||
Organization: "Test",
|
||||
CommonName: "localhost",
|
||||
}
|
||||
cert, err := NewCertificate(info, key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cert.Sign(key, EVP_SHA256); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCAGenerate(t *testing.T) {
|
||||
cakey, err := GenerateRSAKey(2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
info := &CertificateInfo{
|
||||
Serial: 1,
|
||||
Issued: 0,
|
||||
Expires: 24 * time.Hour,
|
||||
Country: "US",
|
||||
Organization: "Test CA",
|
||||
CommonName: "CA",
|
||||
}
|
||||
ca, err := NewCertificate(info, cakey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ca.AddExtensions(map[NID]string{
|
||||
NID_basic_constraints: "critical,CA:TRUE",
|
||||
NID_key_usage: "critical,keyCertSign,cRLSign",
|
||||
NID_subject_key_identifier: "hash",
|
||||
NID_netscape_cert_type: "sslCA",
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ca.Sign(cakey, EVP_SHA256); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
key, err := GenerateRSAKey(2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
info = &CertificateInfo{
|
||||
Serial: 1,
|
||||
Issued: 0,
|
||||
Expires: 24 * time.Hour,
|
||||
Country: "US",
|
||||
Organization: "Test",
|
||||
CommonName: "localhost",
|
||||
}
|
||||
cert, err := NewCertificate(info, key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cert.AddExtensions(map[NID]string{
|
||||
NID_basic_constraints: "critical,CA:FALSE",
|
||||
NID_key_usage: "keyEncipherment",
|
||||
NID_ext_key_usage: "serverAuth",
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cert.SetIssuer(ca); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cert.Sign(cakey, EVP_SHA256); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
@ -73,8 +73,8 @@ type Cipher struct {
|
||||
ptr *C.EVP_CIPHER
|
||||
}
|
||||
|
||||
func (c *Cipher) Nid() int {
|
||||
return int(C.EVP_CIPHER_nid_not_a_macro(c.ptr))
|
||||
func (c *Cipher) Nid() NID {
|
||||
return NID(C.EVP_CIPHER_nid_not_a_macro(c.ptr))
|
||||
}
|
||||
|
||||
func (c *Cipher) ShortName() (string, error) {
|
||||
@ -93,7 +93,7 @@ func (c *Cipher) IVSize() int {
|
||||
return int(C.EVP_CIPHER_iv_length_not_a_macro(c.ptr))
|
||||
}
|
||||
|
||||
func Nid2ShortName(nid int) (string, error) {
|
||||
func Nid2ShortName(nid NID) (string, error) {
|
||||
sn := C.OBJ_nid2sn(C.int(nid))
|
||||
if sn == nil {
|
||||
return "", fmt.Errorf("NID %d not found", nid)
|
||||
@ -112,7 +112,7 @@ func GetCipherByName(name string) (*Cipher, error) {
|
||||
return &Cipher{ptr: p}, nil
|
||||
}
|
||||
|
||||
func GetCipherByNid(nid int) (*Cipher, error) {
|
||||
func GetCipherByNid(nid NID) (*Cipher, error) {
|
||||
sn, err := Nid2ShortName(nid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
11
ctx.go
11
ctx.go
@ -101,6 +101,9 @@ var (
|
||||
|
||||
type Ctx struct {
|
||||
ctx *C.SSL_CTX
|
||||
cert *Certificate
|
||||
chain []*Certificate
|
||||
key PrivateKey
|
||||
verify_cb VerifyCallback
|
||||
}
|
||||
|
||||
@ -244,6 +247,7 @@ func (c *Ctx) SetEllipticCurve(curve EllipticCurve) error {
|
||||
func (c *Ctx) UseCertificate(cert *Certificate) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
c.cert = cert
|
||||
if int(C.SSL_CTX_use_certificate(c.ctx, cert.x)) != 1 {
|
||||
return errorFromErrorQueue()
|
||||
}
|
||||
@ -255,6 +259,7 @@ func (c *Ctx) UseCertificate(cert *Certificate) error {
|
||||
func (c *Ctx) AddChainCertificate(cert *Certificate) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
c.chain = append(c.chain, cert)
|
||||
if int(C.SSL_CTX_add_extra_chain_cert_not_a_macro(c.ctx, cert.x)) != 1 {
|
||||
return errorFromErrorQueue()
|
||||
}
|
||||
@ -266,6 +271,7 @@ func (c *Ctx) AddChainCertificate(cert *Certificate) error {
|
||||
func (c *Ctx) UsePrivateKey(key PrivateKey) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
c.key = key
|
||||
if int(C.SSL_CTX_use_PrivateKey(c.ctx, key.evpPKey())) != 1 {
|
||||
return errorFromErrorQueue()
|
||||
}
|
||||
@ -274,7 +280,9 @@ func (c *Ctx) UsePrivateKey(key PrivateKey) error {
|
||||
|
||||
type CertificateStore struct {
|
||||
store *C.X509_STORE
|
||||
ctx *Ctx // for gc
|
||||
// for GC
|
||||
ctx *Ctx
|
||||
certs []*Certificate
|
||||
}
|
||||
|
||||
// GetCertificateStore returns the context's certificate store that will be
|
||||
@ -292,6 +300,7 @@ func (c *Ctx) GetCertificateStore() *CertificateStore {
|
||||
func (s *CertificateStore) AddCertificate(cert *Certificate) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
s.certs = append(s.certs, cert)
|
||||
if int(C.X509_STORE_add_cert(s.store, cert.x)) != 1 {
|
||||
return errorFromErrorQueue()
|
||||
}
|
||||
|
@ -20,8 +20,6 @@ package openssl
|
||||
// #include <openssl/ssl.h>
|
||||
// #include <openssl/conf.h>
|
||||
//
|
||||
// void OPENSSL_free_not_a_macro(void *ref) { OPENSSL_free(ref); }
|
||||
//
|
||||
// int EVP_SignInit_not_a_macro(EVP_MD_CTX *ctx, const EVP_MD *type) {
|
||||
// return EVP_SignInit(ctx, type);
|
||||
// }
|
||||
@ -312,65 +310,24 @@ func LoadPublicKeyFromDER(der_block []byte) (PublicKey, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
type Certificate struct {
|
||||
x *C.X509
|
||||
ref interface{}
|
||||
}
|
||||
|
||||
// LoadCertificateFromPEM loads an X509 certificate from a PEM-encoded block.
|
||||
func LoadCertificateFromPEM(pem_block []byte) (*Certificate, error) {
|
||||
if len(pem_block) == 0 {
|
||||
return nil, errors.New("empty pem block")
|
||||
// GenerateRSAKey generates a new RSA private key with an exponent of 3.
|
||||
func GenerateRSAKey(bits int) (PrivateKey, error) {
|
||||
exponent := 3
|
||||
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")
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]),
|
||||
C.int(len(pem_block)))
|
||||
cert := C.PEM_read_bio_X509(bio, nil, nil, nil)
|
||||
C.BIO_free(bio)
|
||||
if cert == nil {
|
||||
return nil, errorFromErrorQueue()
|
||||
key := C.EVP_PKEY_new()
|
||||
if key == nil {
|
||||
return nil, errors.New("failed to allocate EVP_PKEY")
|
||||
}
|
||||
x := &Certificate{x: cert}
|
||||
runtime.SetFinalizer(x, func(x *Certificate) {
|
||||
C.X509_free(x.x)
|
||||
if C.EVP_PKEY_assign(key, C.EVP_PKEY_RSA, unsafe.Pointer(rsa)) != 1 {
|
||||
C.EVP_PKEY_free(key)
|
||||
return nil, errors.New("failed to assign RSA key")
|
||||
}
|
||||
p := &pKey{key: key}
|
||||
runtime.SetFinalizer(p, func(p *pKey) {
|
||||
C.EVP_PKEY_free(p.key)
|
||||
})
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// MarshalPEM converts the X509 certificate to PEM-encoded format
|
||||
func (c *Certificate) MarshalPEM() (pem_block []byte, 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)
|
||||
if int(C.PEM_write_bio_X509(bio, c.x)) != 1 {
|
||||
return nil, errors.New("failed dumping certificate")
|
||||
}
|
||||
return ioutil.ReadAll(asAnyBio(bio))
|
||||
}
|
||||
|
||||
// PublicKey returns the public key embedded in the X509 certificate.
|
||||
func (c *Certificate) PublicKey() (PublicKey, error) {
|
||||
pkey := C.X509_get_pubkey(c.x)
|
||||
if pkey == nil {
|
||||
return nil, errors.New("no public key found")
|
||||
}
|
||||
key := &pKey{key: pkey}
|
||||
runtime.SetFinalizer(key, func(key *pKey) {
|
||||
C.EVP_PKEY_free(key.key)
|
||||
})
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// GetSerialNumberHex returns the certificate's serial number in hex format
|
||||
func (c *Certificate) GetSerialNumberHex() (serial string) {
|
||||
asn1_i := C.X509_get_serialNumber(c.x)
|
||||
bignum := C.ASN1_INTEGER_to_BN(asn1_i, nil)
|
||||
hex := C.BN_bn2hex(bignum)
|
||||
serial = C.GoString(hex)
|
||||
C.BN_free(bignum)
|
||||
C.OPENSSL_free_not_a_macro(unsafe.Pointer(hex))
|
||||
return
|
||||
return p, nil
|
||||
}
|
@ -132,3 +132,18 @@ func TestMarshal(t *testing.T) {
|
||||
t.Fatal("invalid public key der bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
key, err := GenerateRSAKey(2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = key.MarshalPKIXPublicKeyPEM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = key.MarshalPKCS1PrivateKeyPEM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
199
nid.go
Normal file
199
nid.go
Normal file
@ -0,0 +1,199 @@
|
||||
// Copyright (C) 2014 Ryan Hileman
|
||||
//
|
||||
// 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.
|
||||
|
||||
package openssl
|
||||
|
||||
type NID int
|
||||
|
||||
const (
|
||||
NID_rsadsi NID = 1
|
||||
NID_pkcs NID = 2
|
||||
NID_md2 NID = 3
|
||||
NID_md5 NID = 4
|
||||
NID_rc4 NID = 5
|
||||
NID_rsaEncryption NID = 6
|
||||
NID_md2WithRSAEncryption NID = 7
|
||||
NID_md5WithRSAEncryption NID = 8
|
||||
NID_pbeWithMD2AndDES_CBC NID = 9
|
||||
NID_pbeWithMD5AndDES_CBC NID = 10
|
||||
NID_X500 NID = 11
|
||||
NID_X509 NID = 12
|
||||
NID_commonName NID = 13
|
||||
NID_countryName NID = 14
|
||||
NID_localityName NID = 15
|
||||
NID_stateOrProvinceName NID = 16
|
||||
NID_organizationName NID = 17
|
||||
NID_organizationalUnitName NID = 18
|
||||
NID_rsa NID = 19
|
||||
NID_pkcs7 NID = 20
|
||||
NID_pkcs7_data NID = 21
|
||||
NID_pkcs7_signed NID = 22
|
||||
NID_pkcs7_enveloped NID = 23
|
||||
NID_pkcs7_signedAndEnveloped NID = 24
|
||||
NID_pkcs7_digest NID = 25
|
||||
NID_pkcs7_encrypted NID = 26
|
||||
NID_pkcs3 NID = 27
|
||||
NID_dhKeyAgreement NID = 28
|
||||
NID_des_ecb NID = 29
|
||||
NID_des_cfb64 NID = 30
|
||||
NID_des_cbc NID = 31
|
||||
NID_des_ede NID = 32
|
||||
NID_des_ede3 NID = 33
|
||||
NID_idea_cbc NID = 34
|
||||
NID_idea_cfb64 NID = 35
|
||||
NID_idea_ecb NID = 36
|
||||
NID_rc2_cbc NID = 37
|
||||
NID_rc2_ecb NID = 38
|
||||
NID_rc2_cfb64 NID = 39
|
||||
NID_rc2_ofb64 NID = 40
|
||||
NID_sha NID = 41
|
||||
NID_shaWithRSAEncryption NID = 42
|
||||
NID_des_ede_cbc NID = 43
|
||||
NID_des_ede3_cbc NID = 44
|
||||
NID_des_ofb64 NID = 45
|
||||
NID_idea_ofb64 NID = 46
|
||||
NID_pkcs9 NID = 47
|
||||
NID_pkcs9_emailAddress NID = 48
|
||||
NID_pkcs9_unstructuredName NID = 49
|
||||
NID_pkcs9_contentType NID = 50
|
||||
NID_pkcs9_messageDigest NID = 51
|
||||
NID_pkcs9_signingTime NID = 52
|
||||
NID_pkcs9_countersignature NID = 53
|
||||
NID_pkcs9_challengePassword NID = 54
|
||||
NID_pkcs9_unstructuredAddress NID = 55
|
||||
NID_pkcs9_extCertAttributes NID = 56
|
||||
NID_netscape NID = 57
|
||||
NID_netscape_cert_extension NID = 58
|
||||
NID_netscape_data_type NID = 59
|
||||
NID_des_ede_cfb64 NID = 60
|
||||
NID_des_ede3_cfb64 NID = 61
|
||||
NID_des_ede_ofb64 NID = 62
|
||||
NID_des_ede3_ofb64 NID = 63
|
||||
NID_sha1 NID = 64
|
||||
NID_sha1WithRSAEncryption NID = 65
|
||||
NID_dsaWithSHA NID = 66
|
||||
NID_dsa_2 NID = 67
|
||||
NID_pbeWithSHA1AndRC2_CBC NID = 68
|
||||
NID_id_pbkdf2 NID = 69
|
||||
NID_dsaWithSHA1_2 NID = 70
|
||||
NID_netscape_cert_type NID = 71
|
||||
NID_netscape_base_url NID = 72
|
||||
NID_netscape_revocation_url NID = 73
|
||||
NID_netscape_ca_revocation_url NID = 74
|
||||
NID_netscape_renewal_url NID = 75
|
||||
NID_netscape_ca_policy_url NID = 76
|
||||
NID_netscape_ssl_server_name NID = 77
|
||||
NID_netscape_comment NID = 78
|
||||
NID_netscape_cert_sequence NID = 79
|
||||
NID_desx_cbc NID = 80
|
||||
NID_id_ce NID = 81
|
||||
NID_subject_key_identifier NID = 82
|
||||
NID_key_usage NID = 83
|
||||
NID_private_key_usage_period NID = 84
|
||||
NID_subject_alt_name NID = 85
|
||||
NID_issuer_alt_name NID = 86
|
||||
NID_basic_constraints NID = 87
|
||||
NID_crl_number NID = 88
|
||||
NID_certificate_policies NID = 89
|
||||
NID_authority_key_identifier NID = 90
|
||||
NID_bf_cbc NID = 91
|
||||
NID_bf_ecb NID = 92
|
||||
NID_bf_cfb64 NID = 93
|
||||
NID_bf_ofb64 NID = 94
|
||||
NID_mdc2 NID = 95
|
||||
NID_mdc2WithRSA NID = 96
|
||||
NID_rc4_40 NID = 97
|
||||
NID_rc2_40_cbc NID = 98
|
||||
NID_givenName NID = 99
|
||||
NID_surname NID = 100
|
||||
NID_initials NID = 101
|
||||
NID_uniqueIdentifier NID = 102
|
||||
NID_crl_distribution_points NID = 103
|
||||
NID_md5WithRSA NID = 104
|
||||
NID_serialNumber NID = 105
|
||||
NID_title NID = 106
|
||||
NID_description NID = 107
|
||||
NID_cast5_cbc NID = 108
|
||||
NID_cast5_ecb NID = 109
|
||||
NID_cast5_cfb64 NID = 110
|
||||
NID_cast5_ofb64 NID = 111
|
||||
NID_pbeWithMD5AndCast5_CBC NID = 112
|
||||
NID_dsaWithSHA1 NID = 113
|
||||
NID_md5_sha1 NID = 114
|
||||
NID_sha1WithRSA NID = 115
|
||||
NID_dsa NID = 116
|
||||
NID_ripemd160 NID = 117
|
||||
NID_ripemd160WithRSA NID = 119
|
||||
NID_rc5_cbc NID = 120
|
||||
NID_rc5_ecb NID = 121
|
||||
NID_rc5_cfb64 NID = 122
|
||||
NID_rc5_ofb64 NID = 123
|
||||
NID_rle_compression NID = 124
|
||||
NID_zlib_compression NID = 125
|
||||
NID_ext_key_usage NID = 126
|
||||
NID_id_pkix NID = 127
|
||||
NID_id_kp NID = 128
|
||||
NID_server_auth NID = 129
|
||||
NID_client_auth NID = 130
|
||||
NID_code_sign NID = 131
|
||||
NID_email_protect NID = 132
|
||||
NID_time_stamp NID = 133
|
||||
NID_ms_code_ind NID = 134
|
||||
NID_ms_code_com NID = 135
|
||||
NID_ms_ctl_sign NID = 136
|
||||
NID_ms_sgc NID = 137
|
||||
NID_ms_efs NID = 138
|
||||
NID_ns_sgc NID = 139
|
||||
NID_delta_crl NID = 140
|
||||
NID_crl_reason NID = 141
|
||||
NID_invalidity_date NID = 142
|
||||
NID_sxnet NID = 143
|
||||
NID_pbe_WithSHA1And128BitRC4 NID = 144
|
||||
NID_pbe_WithSHA1And40BitRC4 NID = 145
|
||||
NID_pbe_WithSHA1And3_Key_TripleDES_CBC NID = 146
|
||||
NID_pbe_WithSHA1And2_Key_TripleDES_CBC NID = 147
|
||||
NID_pbe_WithSHA1And128BitRC2_CBC NID = 148
|
||||
NID_pbe_WithSHA1And40BitRC2_CBC NID = 149
|
||||
NID_keyBag NID = 150
|
||||
NID_pkcs8ShroudedKeyBag NID = 151
|
||||
NID_certBag NID = 152
|
||||
NID_crlBag NID = 153
|
||||
NID_secretBag NID = 154
|
||||
NID_safeContentsBag NID = 155
|
||||
NID_friendlyName NID = 156
|
||||
NID_localKeyID NID = 157
|
||||
NID_x509Certificate NID = 158
|
||||
NID_sdsiCertificate NID = 159
|
||||
NID_x509Crl NID = 160
|
||||
NID_pbes2 NID = 161
|
||||
NID_pbmac1 NID = 162
|
||||
NID_hmacWithSHA1 NID = 163
|
||||
NID_id_qt_cps NID = 164
|
||||
NID_id_qt_unotice NID = 165
|
||||
NID_rc2_64_cbc NID = 166
|
||||
NID_SMIMECapabilities NID = 167
|
||||
NID_pbeWithMD2AndRC2_CBC NID = 168
|
||||
NID_pbeWithMD5AndRC2_CBC NID = 169
|
||||
NID_pbeWithSHA1AndDES_CBC NID = 170
|
||||
NID_ms_ext_req NID = 171
|
||||
NID_ext_req NID = 172
|
||||
NID_name NID = 173
|
||||
NID_dnQualifier NID = 174
|
||||
NID_id_pe NID = 175
|
||||
NID_id_ad NID = 176
|
||||
NID_info_access NID = 177
|
||||
NID_ad_OCSP NID = 178
|
||||
NID_ad_ca_issuers NID = 179
|
||||
NID_OCSP_sign NID = 180
|
||||
)
|
Loading…
Reference in New Issue
Block a user