reformat everything with gofmt
Yes, I know that this will more or less destroy the history, but it had to be done. I also adjusted my editor to use gofmt rules by default now.
This commit is contained in:
parent
b3f621a312
commit
301d931ad7
192
certificate.go
192
certificate.go
|
@ -1,83 +1,87 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"time"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// labels used in the pem file format to mark certificate sign requests and certificates
|
||||
const (
|
||||
PemLabelCertificateRequest = "CERTIFICATE REQUEST"
|
||||
PemLabelCertificate = "CERTIFICATE"
|
||||
PemLabelCertificateRequest = "CERTIFICATE REQUEST"
|
||||
PemLabelCertificate = "CERTIFICATE"
|
||||
)
|
||||
|
||||
type (
|
||||
// Use CertificateData to fill in the minimum data you need to create a certificate
|
||||
// sign request.
|
||||
CertificateData struct {
|
||||
Subject pkix.Name
|
||||
// Use CertificateData to fill in the minimum data you need to create a certificate
|
||||
// sign request.
|
||||
CertificateData struct {
|
||||
Subject pkix.Name
|
||||
|
||||
DNSNames []string
|
||||
EmailAddresses []string
|
||||
IPAddresses []net.IP
|
||||
}
|
||||
DNSNames []string
|
||||
EmailAddresses []string
|
||||
IPAddresses []net.IP
|
||||
}
|
||||
|
||||
// Certificate is an alias on the x509.Certificate to add some methods.
|
||||
Certificate x509.Certificate
|
||||
// CertificateRequest is an alias on the x509.CertificateRequest to add some methods.
|
||||
CertificateRequest x509.CertificateRequest
|
||||
// Certificate is an alias on the x509.Certificate to add some methods.
|
||||
Certificate x509.Certificate
|
||||
// CertificateRequest is an alias on the x509.CertificateRequest to add some methods.
|
||||
CertificateRequest x509.CertificateRequest
|
||||
|
||||
// CertificateOptions is used to provide the necessary information to create
|
||||
// a certificate from a certificate sign request.
|
||||
CertificateOptions struct {
|
||||
SerialNumber *big.Int
|
||||
NotBefore time.Time
|
||||
NotAfter time.Time // Validity bounds.
|
||||
IsCA bool
|
||||
// how many sub ca are allowed between this ca and the end/final certificate
|
||||
// if it is -1, then no limit will be set
|
||||
CALength int
|
||||
KeyUsage x509.KeyUsage
|
||||
}
|
||||
// CertificateOptions is used to provide the necessary information to create
|
||||
// a certificate from a certificate sign request.
|
||||
CertificateOptions struct {
|
||||
SerialNumber *big.Int
|
||||
NotBefore time.Time
|
||||
NotAfter time.Time // Validity bounds.
|
||||
IsCA bool
|
||||
// how many sub ca are allowed between this ca and the end/final certificate
|
||||
// if it is -1, then no limit will be set
|
||||
CALength int
|
||||
KeyUsage x509.KeyUsage
|
||||
}
|
||||
)
|
||||
|
||||
// Create a new set of certificate data.
|
||||
func NewCertificateData() *CertificateData {
|
||||
return &CertificateData{Subject: pkix.Name{}}
|
||||
return &CertificateData{Subject: pkix.Name{}}
|
||||
}
|
||||
|
||||
// Create a certificate sign request from the input data and the private key of
|
||||
// the request creator.
|
||||
func (c *CertificateData) ToCertificateRequest(private_key PrivateKey) (*CertificateRequest, error) {
|
||||
csr := &x509.CertificateRequest{}
|
||||
csr := &x509.CertificateRequest{}
|
||||
|
||||
csr.Subject = c.Subject
|
||||
csr.DNSNames = c.DNSNames
|
||||
csr.IPAddresses = c.IPAddresses
|
||||
csr.EmailAddresses = c.EmailAddresses
|
||||
csr.Subject = c.Subject
|
||||
csr.DNSNames = c.DNSNames
|
||||
csr.IPAddresses = c.IPAddresses
|
||||
csr.EmailAddresses = c.EmailAddresses
|
||||
|
||||
csr_asn1, err := x509.CreateCertificateRequest(rand.Reader, csr, private_key.PrivateKey())
|
||||
if err != nil { return nil, err }
|
||||
return LoadCertificateSignRequest(csr_asn1)
|
||||
csr_asn1, err := x509.CreateCertificateRequest(rand.Reader, csr, private_key.PrivateKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return LoadCertificateSignRequest(csr_asn1)
|
||||
}
|
||||
|
||||
// Load a certificate sign request from its asn1 representation.
|
||||
func LoadCertificateSignRequest(raw []byte) (*CertificateRequest, error) {
|
||||
csr, err := x509.ParseCertificateRequest(raw)
|
||||
if err != nil { return nil, err }
|
||||
return (*CertificateRequest)(csr), nil
|
||||
csr, err := x509.ParseCertificateRequest(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*CertificateRequest)(csr), nil
|
||||
}
|
||||
|
||||
// Return the certificate sign request as a pem block.
|
||||
func (c *CertificateRequest) MarshalPem() (marshalledPemBlock, error) {
|
||||
block := &pem.Block{Type: PemLabelCertificateRequest, Bytes: c.Raw}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
block := &pem.Block{Type: PemLabelCertificateRequest, Bytes: c.Raw}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
|
||||
// Convert the certificate sign request to a certificate using the private key
|
||||
|
@ -86,63 +90,71 @@ func (c *CertificateRequest) MarshalPem() (marshalledPemBlock, error) {
|
|||
// Please also see the certificate options struct for information on mandatory fields.
|
||||
// For more information, please read http://golang.org/pkg/crypto/x509/#CreateCertificate
|
||||
func (c *CertificateRequest) ToCertificate(private_key PrivateKey,
|
||||
cert_opts CertificateOptions, ca *Certificate) (*Certificate, error) {
|
||||
cert_opts CertificateOptions, ca *Certificate) (*Certificate, error) {
|
||||
|
||||
if err := cert_opts.Valid(); err != nil { return nil, err }
|
||||
if err := cert_opts.Valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
template := &x509.Certificate{}
|
||||
template.Subject = c.Subject
|
||||
template.DNSNames = c.DNSNames
|
||||
template.IPAddresses = c.IPAddresses
|
||||
template.EmailAddresses = c.EmailAddresses
|
||||
template := &x509.Certificate{}
|
||||
template.Subject = c.Subject
|
||||
template.DNSNames = c.DNSNames
|
||||
template.IPAddresses = c.IPAddresses
|
||||
template.EmailAddresses = c.EmailAddresses
|
||||
|
||||
// if no ca is given, we have to set IsCA to self sign
|
||||
if ca == nil {
|
||||
template.IsCA = true
|
||||
}
|
||||
// if no ca is given, we have to set IsCA to self sign
|
||||
if ca == nil {
|
||||
template.IsCA = true
|
||||
}
|
||||
|
||||
template.NotBefore = cert_opts.NotBefore
|
||||
template.NotAfter = cert_opts.NotAfter
|
||||
template.KeyUsage = cert_opts.KeyUsage
|
||||
template.IsCA = cert_opts.IsCA
|
||||
if cert_opts.IsCA {
|
||||
template.BasicConstraintsValid = true
|
||||
}
|
||||
if cert_opts.CALength >= 0 {
|
||||
template.MaxPathLen = cert_opts.CALength
|
||||
template.MaxPathLenZero = true
|
||||
template.BasicConstraintsValid = true
|
||||
}
|
||||
template.SerialNumber = cert_opts.SerialNumber
|
||||
template.NotBefore = cert_opts.NotBefore
|
||||
template.NotAfter = cert_opts.NotAfter
|
||||
template.KeyUsage = cert_opts.KeyUsage
|
||||
template.IsCA = cert_opts.IsCA
|
||||
if cert_opts.IsCA {
|
||||
template.BasicConstraintsValid = true
|
||||
}
|
||||
if cert_opts.CALength >= 0 {
|
||||
template.MaxPathLen = cert_opts.CALength
|
||||
template.MaxPathLenZero = true
|
||||
template.BasicConstraintsValid = true
|
||||
}
|
||||
template.SerialNumber = cert_opts.SerialNumber
|
||||
|
||||
var cert_asn1 []byte
|
||||
var err error
|
||||
// if we have no ca which can sign the cert, a self signed cert is wanted
|
||||
// (or isn't it? Maybe we should split creation of the template? But that would be ugly)
|
||||
if ca == nil {
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, template, c.PublicKey, private_key.PrivateKey())
|
||||
} else {
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, (*x509.Certificate)(ca), c.PublicKey, private_key.PrivateKey())
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
return LoadCertificate(cert_asn1)
|
||||
var cert_asn1 []byte
|
||||
var err error
|
||||
// if we have no ca which can sign the cert, a self signed cert is wanted
|
||||
// (or isn't it? Maybe we should split creation of the template? But that would be ugly)
|
||||
if ca == nil {
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, template, c.PublicKey, private_key.PrivateKey())
|
||||
} else {
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, (*x509.Certificate)(ca), c.PublicKey, private_key.PrivateKey())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return LoadCertificate(cert_asn1)
|
||||
}
|
||||
|
||||
// Load a certificate from its asn1 representation.
|
||||
func LoadCertificate(raw []byte) (*Certificate, error) {
|
||||
cert, err := x509.ParseCertificate(raw)
|
||||
if err != nil { return nil, err }
|
||||
return (*Certificate)(cert), nil
|
||||
cert, err := x509.ParseCertificate(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*Certificate)(cert), nil
|
||||
}
|
||||
|
||||
// marshal the certificate to a pem block
|
||||
func (c *Certificate) MarshalPem() (marshalledPemBlock, error) {
|
||||
block := &pem.Block{Type: PemLabelCertificate, Bytes: c.Raw}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
block := &pem.Block{Type: PemLabelCertificate, Bytes: c.Raw}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
|
||||
// Check if the certificate options have the required fields set.
|
||||
func (co *CertificateOptions) Valid() error {
|
||||
if co.SerialNumber == nil { return fmt.Errorf("No serial number set!") }
|
||||
return nil
|
||||
if co.SerialNumber == nil {
|
||||
return fmt.Errorf("No serial number set!")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,46 +1,61 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
// "crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
"crypto/elliptic"
|
||||
"crypto/x509/pkix"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
TestCertificateData = CertificateData{
|
||||
Subject: pkix.Name{CommonName: "foobar"},
|
||||
DNSNames: []string{"foo.bar", "example.com"},
|
||||
}
|
||||
TestCertificateData = CertificateData{
|
||||
Subject: pkix.Name{CommonName: "foobar"},
|
||||
DNSNames: []string{"foo.bar", "example.com"},
|
||||
}
|
||||
)
|
||||
|
||||
func TestCertificateCreation(t *testing.T) {
|
||||
pk, err := NewPrivateKeyEcdsa(elliptic.P224())
|
||||
if err != nil { t.Errorf("cert: creating private key failed: %s", err) }
|
||||
pk, err := NewPrivateKeyEcdsa(elliptic.P224())
|
||||
if err != nil {
|
||||
t.Errorf("cert: creating private key failed: %s", err)
|
||||
}
|
||||
|
||||
csr, err := TestCertificateData.ToCertificateRequest(pk)
|
||||
if err != nil { t.Errorf("cert: creating csr failed: %s", err) }
|
||||
csr, err := TestCertificateData.ToCertificateRequest(pk)
|
||||
if err != nil {
|
||||
t.Errorf("cert: creating csr failed: %s", err)
|
||||
}
|
||||
|
||||
cert_opts := CertificateOptions{
|
||||
// KeyUsage: x509.KeyUsageEncipherOnly | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
|
||||
SerialNumber: big.NewInt(1),
|
||||
}
|
||||
cert_opts := CertificateOptions{
|
||||
// KeyUsage: x509.KeyUsageEncipherOnly | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
|
||||
SerialNumber: big.NewInt(1),
|
||||
}
|
||||
|
||||
cert, err := csr.ToCertificate(pk, cert_opts, nil)
|
||||
if err != nil { t.Errorf("cert: creating cert failed: %s", err) }
|
||||
cert, err := csr.ToCertificate(pk, cert_opts, nil)
|
||||
if err != nil {
|
||||
t.Errorf("cert: creating cert failed: %s", err)
|
||||
}
|
||||
|
||||
if !fieldsAreSame(TestCertificateData, cert) {
|
||||
t.Errorf("cert: Fields are not the same")
|
||||
}
|
||||
if !fieldsAreSame(TestCertificateData, cert) {
|
||||
t.Errorf("cert: Fields are not the same")
|
||||
}
|
||||
}
|
||||
|
||||
func fieldsAreSame(data CertificateData, cert *Certificate) bool {
|
||||
if data.Subject.CommonName != cert.Subject.CommonName { return false }
|
||||
if !reflect.DeepEqual(data.Subject.Country, cert.Subject.Country) { return false }
|
||||
if !reflect.DeepEqual(data.DNSNames, cert.DNSNames) { return false }
|
||||
if !reflect.DeepEqual(data.IPAddresses, cert.IPAddresses) { return false }
|
||||
if !reflect.DeepEqual(data.EmailAddresses, cert.EmailAddresses) { return false }
|
||||
return true
|
||||
if data.Subject.CommonName != cert.Subject.CommonName {
|
||||
return false
|
||||
}
|
||||
if !reflect.DeepEqual(data.Subject.Country, cert.Subject.Country) {
|
||||
return false
|
||||
}
|
||||
if !reflect.DeepEqual(data.DNSNames, cert.DNSNames) {
|
||||
return false
|
||||
}
|
||||
if !reflect.DeepEqual(data.IPAddresses, cert.IPAddresses) {
|
||||
return false
|
||||
}
|
||||
if !reflect.DeepEqual(data.EmailAddresses, cert.EmailAddresses) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
130
ecdsa.go
130
ecdsa.go
|
@ -1,112 +1,126 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// This label is used as the type in the pem encoding of ECDSA private keys.
|
||||
const PemLabelEcdsa = "EC PRIVATE KEY"
|
||||
|
||||
type (
|
||||
// This type handles the function calls to the ecdsa private key by
|
||||
// implementing the interface.
|
||||
EcdsaPrivateKey struct {
|
||||
private_key *ecdsa.PrivateKey
|
||||
}
|
||||
// This type handles the function calls to the ecdsa private key by
|
||||
// implementing the interface.
|
||||
EcdsaPrivateKey struct {
|
||||
private_key *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
// EcdsaPublicKey is the specific public key type for ecdsa. It implements the
|
||||
// the PublicKey interface.
|
||||
EcdsaPublicKey struct {
|
||||
public_key *ecdsa.PublicKey
|
||||
}
|
||||
// EcdsaPublicKey is the specific public key type for ecdsa. It implements the
|
||||
// the PublicKey interface.
|
||||
EcdsaPublicKey struct {
|
||||
public_key *ecdsa.PublicKey
|
||||
}
|
||||
|
||||
// This struct is used to marshal and parse the ecdsa signature.
|
||||
signatureEcdsa struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
// This struct is used to marshal and parse the ecdsa signature.
|
||||
signatureEcdsa struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
)
|
||||
|
||||
// Create a new ECDSA private key using the specified curve.
|
||||
// For available curves, please take a look at the crypto/elliptic package.
|
||||
func NewPrivateKeyEcdsa(curve elliptic.Curve) (*EcdsaPrivateKey, error) {
|
||||
key, err := ecdsa.GenerateKey(curve, rand.Reader)
|
||||
if err != nil { return nil, err }
|
||||
return &EcdsaPrivateKey{key}, nil
|
||||
key, err := ecdsa.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &EcdsaPrivateKey{key}, nil
|
||||
}
|
||||
|
||||
// Load the private key from the asn1 representation.
|
||||
func LoadPrivateKeyEcdsa(raw []byte) (*EcdsaPrivateKey, error) {
|
||||
key, err := x509.ParseECPrivateKey(raw)
|
||||
if err != nil { return nil, err }
|
||||
return &EcdsaPrivateKey{key}, nil
|
||||
key, err := x509.ParseECPrivateKey(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &EcdsaPrivateKey{key}, nil
|
||||
}
|
||||
|
||||
// Create a new public key from the private key.
|
||||
func (pr EcdsaPrivateKey) Public() PublicKey {
|
||||
return &EcdsaPublicKey{pr.private_key.Public().(*ecdsa.PublicKey)}
|
||||
return &EcdsaPublicKey{pr.private_key.Public().(*ecdsa.PublicKey)}
|
||||
}
|
||||
|
||||
// Sign a message using the private key and the provided hash function.
|
||||
func (pr EcdsaPrivateKey) Sign(message []byte, hash crypto.Hash) ([]byte, error) {
|
||||
empty := make([]byte, 0)
|
||||
if !hash.Available() {
|
||||
return empty, errors.New("Hash method is not available!")
|
||||
}
|
||||
hashed_message := hash.New()
|
||||
hashed_message.Write(message)
|
||||
return pr.private_key.Sign(rand.Reader, hashed_message.Sum(nil), hash)
|
||||
empty := make([]byte, 0)
|
||||
if !hash.Available() {
|
||||
return empty, errors.New("Hash method is not available!")
|
||||
}
|
||||
hashed_message := hash.New()
|
||||
hashed_message.Write(message)
|
||||
return pr.private_key.Sign(rand.Reader, hashed_message.Sum(nil), hash)
|
||||
}
|
||||
|
||||
// This function returns the crypto.PrivateKey structure of the ECDSA key.
|
||||
func (pr EcdsaPrivateKey) PrivateKey() crypto.PrivateKey {
|
||||
return pr.private_key
|
||||
return pr.private_key
|
||||
}
|
||||
|
||||
// This function implements the Pemmer interface to marshal the private key
|
||||
// into a pem block.
|
||||
func (pr EcdsaPrivateKey) MarshalPem() (io.WriterTo, error) {
|
||||
asn1, err := x509.MarshalECPrivateKey(pr.private_key)
|
||||
if err != nil { return nil, err }
|
||||
pem_block := pem.Block{Type: PemLabelEcdsa, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
asn1, err := x509.MarshalECPrivateKey(pr.private_key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pem_block := pem.Block{Type: PemLabelEcdsa, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
}
|
||||
|
||||
// This functoin loads an ecdsa public key from the asn.1 representation.
|
||||
func LoadPublicKeyEcdsa(raw []byte) (*EcdsaPublicKey, error) {
|
||||
raw_pub, err := x509.ParsePKIXPublicKey(raw)
|
||||
if err != nil { return nil, err }
|
||||
raw_pub, err := x509.ParsePKIXPublicKey(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pub, ok := raw_pub.(*ecdsa.PublicKey)
|
||||
if !ok { return nil, errors.New("Not an ecdsa key!") }
|
||||
return &EcdsaPublicKey{pub}, nil
|
||||
pub, ok := raw_pub.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("Not an ecdsa key!")
|
||||
}
|
||||
return &EcdsaPublicKey{pub}, nil
|
||||
}
|
||||
|
||||
// This function implements the Pemmer interface to marshal the public key into
|
||||
// a pem block.
|
||||
func (pu *EcdsaPublicKey) MarshalPem() (io.WriterTo, error) {
|
||||
asn1, err := x509.MarshalPKIXPublicKey(pu.public_key)
|
||||
if err != nil { return nil, err }
|
||||
pem_block := pem.Block{Type: PemLabelPublic, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
asn1, err := x509.MarshalPKIXPublicKey(pu.public_key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pem_block := pem.Block{Type: PemLabelPublic, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
}
|
||||
|
||||
// This function verifies a message using the public key, signature and hash
|
||||
// function.
|
||||
// The hash function must be the same as was used to create the signature.
|
||||
func (pu *EcdsaPublicKey) Verify(message []byte, signature_raw []byte, hash crypto.Hash) (bool, error) {
|
||||
var sig signatureEcdsa
|
||||
_, err := asn1.Unmarshal(signature_raw, &sig)
|
||||
if err != nil { return false, err }
|
||||
hashed_message := hash.New()
|
||||
hashed_message.Write(message)
|
||||
return ecdsa.Verify(pu.public_key, hashed_message.Sum(nil), sig.R, sig.S), nil
|
||||
var sig signatureEcdsa
|
||||
_, err := asn1.Unmarshal(signature_raw, &sig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
hashed_message := hash.New()
|
||||
hashed_message.Write(message)
|
||||
return ecdsa.Verify(pu.public_key, hashed_message.Sum(nil), sig.R, sig.S), nil
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io"
|
||||
)
|
||||
|
||||
type (
|
||||
marshalledPemBlock []byte
|
||||
marshalledPemBlock []byte
|
||||
)
|
||||
|
||||
// This function writes the marshalled pem block to a writer and returns the
|
||||
// number of written bytes and eventual errors.
|
||||
func (b marshalledPemBlock) WriteTo(stream io.Writer) (int64, error) {
|
||||
numBytes, err := stream.Write(b)
|
||||
return int64(numBytes), err
|
||||
numBytes, err := stream.Write(b)
|
||||
return int64(numBytes), err
|
||||
}
|
||||
|
|
|
@ -1,84 +1,109 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/elliptic"
|
||||
"encoding/pem"
|
||||
"testing"
|
||||
"crypto"
|
||||
"crypto/elliptic"
|
||||
"encoding/pem"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
SignatureMessage = []byte("foobar")
|
||||
SignatureHash = crypto.SHA512
|
||||
SignatureMessage = []byte("foobar")
|
||||
SignatureHash = crypto.SHA512
|
||||
)
|
||||
|
||||
type (
|
||||
Loader func(raw []byte) (PublicKey, error)
|
||||
Loader func(raw []byte) (PublicKey, error)
|
||||
)
|
||||
|
||||
// run the marshal test
|
||||
func RunMarshalTest(pkType string, pe Pemmer, label string, t *testing.T) ([]byte, error) {
|
||||
marshPem, err := pe.MarshalPem()
|
||||
if err != nil {
|
||||
t.Errorf("%s: marshal pem not working: %s", pkType, err)
|
||||
return nil, err
|
||||
}
|
||||
marshPem, err := pe.MarshalPem()
|
||||
if err != nil {
|
||||
t.Errorf("%s: marshal pem not working: %s", pkType, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(marshPem)
|
||||
if block.Type != label {
|
||||
t.Errorf("%s: marshalled pem wrong: %s", pkType, err)
|
||||
return nil, err
|
||||
}
|
||||
return block.Bytes, nil
|
||||
block, _ := pem.Decode(marshPem)
|
||||
if block.Type != label {
|
||||
t.Errorf("%s: marshalled pem wrong: %s", pkType, err)
|
||||
return nil, err
|
||||
}
|
||||
return block.Bytes, nil
|
||||
}
|
||||
|
||||
// test other private key functions
|
||||
func RunPrivateKeyTests(pkType string, pk PrivateKey, pu PublicKey, t *testing.T) {
|
||||
signature, err := pk.Sign(SignatureMessage, SignatureHash)
|
||||
if err != nil { t.Errorf("%s: error creating a signature: %s", pkType, err) }
|
||||
signature, err := pk.Sign(SignatureMessage, SignatureHash)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error creating a signature: %s", pkType, err)
|
||||
}
|
||||
|
||||
valid, err := pu.Verify(SignatureMessage, signature, SignatureHash)
|
||||
if err != nil { t.Errorf("%s: could not verify message: %s", pkType, err) }
|
||||
if !valid { t.Errorf("%s: signature invalid, but should be valid!", pkType) }
|
||||
valid, err := pu.Verify(SignatureMessage, signature, SignatureHash)
|
||||
if err != nil {
|
||||
t.Errorf("%s: could not verify message: %s", pkType, err)
|
||||
}
|
||||
if !valid {
|
||||
t.Errorf("%s: signature invalid, but should be valid!", pkType)
|
||||
}
|
||||
}
|
||||
|
||||
// test ecdsa private key functions
|
||||
func TestEcdsaFunctions(t *testing.T) {
|
||||
pk, err := NewPrivateKeyEcdsa(elliptic.P521())
|
||||
if err != nil { t.Errorf("ecdsa: creating private key failed: %s", err) }
|
||||
pk, err := NewPrivateKeyEcdsa(elliptic.P521())
|
||||
if err != nil {
|
||||
t.Errorf("ecdsa: creating private key failed: %s", err)
|
||||
}
|
||||
|
||||
blockBytes, err := RunMarshalTest("ecdsa", pk, PemLabelEcdsa, t)
|
||||
if err != nil { return }
|
||||
blockBytes, err := RunMarshalTest("ecdsa", pk, PemLabelEcdsa, t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pk, err = LoadPrivateKeyEcdsa(blockBytes)
|
||||
if err != nil { t.Errorf("ecdsa: pem content wrong: %s", err) }
|
||||
pk, err = LoadPrivateKeyEcdsa(blockBytes)
|
||||
if err != nil {
|
||||
t.Errorf("ecdsa: pem content wrong: %s", err)
|
||||
}
|
||||
|
||||
blockBytes, err = RunMarshalTest("ecdsa-public", pk.Public(), PemLabelPublic, t)
|
||||
if err != nil { return }
|
||||
blockBytes, err = RunMarshalTest("ecdsa-public", pk.Public(), PemLabelPublic, t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pu, err := LoadPublicKeyEcdsa(blockBytes)
|
||||
if err != nil { t.Errorf("ecdsa-public: pem content wrong: %s", err) }
|
||||
pu, err := LoadPublicKeyEcdsa(blockBytes)
|
||||
if err != nil {
|
||||
t.Errorf("ecdsa-public: pem content wrong: %s", err)
|
||||
}
|
||||
|
||||
RunPrivateKeyTests("ecdsa", pk, pu, t)
|
||||
RunPrivateKeyTests("ecdsa", pk, pu, t)
|
||||
}
|
||||
|
||||
// test rsa private key functions
|
||||
func TestRsaFunctions(t *testing.T) {
|
||||
pk, err := NewPrivateKeyRsa(2048)
|
||||
if err != nil { t.Errorf("rsa: creating private key failed: %s", err) }
|
||||
pk, err := NewPrivateKeyRsa(2048)
|
||||
if err != nil {
|
||||
t.Errorf("rsa: creating private key failed: %s", err)
|
||||
}
|
||||
|
||||
blockBytes, err := RunMarshalTest("rsa", pk, PemLabelRsa, t)
|
||||
if err != nil { return }
|
||||
blockBytes, err := RunMarshalTest("rsa", pk, PemLabelRsa, t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pk, err = LoadPrivateKeyRsa(blockBytes)
|
||||
if err != nil { t.Errorf("rsa: pem content wrong: %s", err) }
|
||||
pk, err = LoadPrivateKeyRsa(blockBytes)
|
||||
if err != nil {
|
||||
t.Errorf("rsa: pem content wrong: %s", err)
|
||||
}
|
||||
|
||||
blockBytes, err = RunMarshalTest("rsa-public", pk.Public(), PemLabelPublic, t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
blockBytes, err = RunMarshalTest("rsa-public", pk.Public(), PemLabelPublic, t)
|
||||
if err != nil { return }
|
||||
pu, err := LoadPublicKeyRsa(blockBytes)
|
||||
if err != nil {
|
||||
t.Errorf("rsa-public: pem content wrong: %s", err)
|
||||
}
|
||||
|
||||
pu, err := LoadPublicKeyRsa(blockBytes)
|
||||
if err != nil { t.Errorf("rsa-public: pem content wrong: %s", err) }
|
||||
|
||||
RunPrivateKeyTests("rsa", pk, pu, t)
|
||||
RunPrivateKeyTests("rsa", pk, pu, t)
|
||||
}
|
||||
|
|
70
rsa.go
70
rsa.go
|
@ -1,76 +1,82 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
PemLabelRsa = "RSA PRIVATE KEY"
|
||||
PemLabelRsa = "RSA PRIVATE KEY"
|
||||
)
|
||||
|
||||
type (
|
||||
RsaPrivateKey struct {
|
||||
private_key *rsa.PrivateKey
|
||||
}
|
||||
RsaPrivateKey struct {
|
||||
private_key *rsa.PrivateKey
|
||||
}
|
||||
|
||||
RsaPublicKey struct {
|
||||
public_key *rsa.PublicKey
|
||||
}
|
||||
RsaPublicKey struct {
|
||||
public_key *rsa.PublicKey
|
||||
}
|
||||
)
|
||||
|
||||
// generate a new rsa private key
|
||||
func NewPrivateKeyRsa(size int) (*RsaPrivateKey, error) {
|
||||
key, err := rsa.GenerateKey(rand.Reader, size)
|
||||
if err != nil { return nil, err }
|
||||
return &RsaPrivateKey{key}, nil
|
||||
key, err := rsa.GenerateKey(rand.Reader, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RsaPrivateKey{key}, nil
|
||||
}
|
||||
|
||||
// load a rsa private key its ASN.1 presentation
|
||||
func LoadPrivateKeyRsa(raw []byte) (*RsaPrivateKey, error) {
|
||||
key, err := x509.ParsePKCS1PrivateKey(raw)
|
||||
if err != nil { return nil, err }
|
||||
return &RsaPrivateKey{key}, nil
|
||||
key, err := x509.ParsePKCS1PrivateKey(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RsaPrivateKey{key}, nil
|
||||
}
|
||||
|
||||
func (pr *RsaPrivateKey) Public() PublicKey {
|
||||
return &RsaPublicKey{pr.private_key.Public().(*rsa.PublicKey)}
|
||||
return &RsaPublicKey{pr.private_key.Public().(*rsa.PublicKey)}
|
||||
}
|
||||
|
||||
func (pr RsaPrivateKey) Sign(message []byte, hash crypto.Hash) ([]byte, error) {
|
||||
return make([]byte, 0), errors.New("not implemented yet!")
|
||||
return make([]byte, 0), errors.New("not implemented yet!")
|
||||
}
|
||||
|
||||
// get the private key
|
||||
func (pr RsaPrivateKey) PrivateKey() crypto.PrivateKey {
|
||||
return pr.private_key
|
||||
return pr.private_key
|
||||
}
|
||||
|
||||
func (pr RsaPrivateKey) MarshalPem() (io.WriterTo, error) {
|
||||
asn1 := x509.MarshalPKCS1PrivateKey(pr.private_key)
|
||||
pem_block := pem.Block{Type: PemLabelRsa, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
asn1 := x509.MarshalPKCS1PrivateKey(pr.private_key)
|
||||
pem_block := pem.Block{Type: PemLabelRsa, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
}
|
||||
|
||||
// restore a rsa public key
|
||||
func LoadPublicKeyRsa(raw []byte) (*RsaPublicKey, error) {
|
||||
return nil, errors.New("not implemented yet!")
|
||||
return nil, errors.New("not implemented yet!")
|
||||
}
|
||||
|
||||
// marshal a rsa public key into pem format
|
||||
func (pu *RsaPublicKey) MarshalPem() (io.WriterTo, error) {
|
||||
asn1, err := x509.MarshalPKIXPublicKey(pu.public_key)
|
||||
if err != nil { return nil, err }
|
||||
pem_block := pem.Block{Type: PemLabelPublic, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
asn1, err := x509.MarshalPKIXPublicKey(pu.public_key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pem_block := pem.Block{Type: PemLabelPublic, Bytes: asn1}
|
||||
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
|
||||
}
|
||||
|
||||
// verify a message with a signature using the public key
|
||||
func (pu *RsaPublicKey) Verify(message []byte, signature []byte, hash crypto.Hash) (bool, error) {
|
||||
return false, errors.New("not implemented yet!")
|
||||
return false, errors.New("not implemented yet!")
|
||||
}
|
||||
|
|
56
types.go
56
types.go
|
@ -15,41 +15,41 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"io"
|
||||
"crypto"
|
||||
"io"
|
||||
)
|
||||
|
||||
// This label is used as the type in the pem encoding of public keys.
|
||||
const PemLabelPublic = "PUBLIC KEY"
|
||||
|
||||
type (
|
||||
// PrivateKey is a common interface for all crypto implementations to provide
|
||||
// the same functions, like deriving a public key or signing a message.
|
||||
PrivateKey interface {
|
||||
// Derive a new public key from the private key.
|
||||
Public() PublicKey
|
||||
// Sign a message using the public key and the given hash method.
|
||||
// To use a hash method, include the package
|
||||
// import _ "crypto/sha512"
|
||||
Sign(message []byte, hash crypto.Hash) ([]byte, error)
|
||||
// PrivateKey is a common interface for all crypto implementations to provide
|
||||
// the same functions, like deriving a public key or signing a message.
|
||||
PrivateKey interface {
|
||||
// Derive a new public key from the private key.
|
||||
Public() PublicKey
|
||||
// Sign a message using the public key and the given hash method.
|
||||
// To use a hash method, include the package
|
||||
// import _ "crypto/sha512"
|
||||
Sign(message []byte, hash crypto.Hash) ([]byte, error)
|
||||
|
||||
// Return the original go structure of the private key.
|
||||
PrivateKey() crypto.PrivateKey
|
||||
}
|
||||
// Return the original go structure of the private key.
|
||||
PrivateKey() crypto.PrivateKey
|
||||
}
|
||||
|
||||
// PublicKey is used by the different crypto implementations to provide the
|
||||
// same functionality like verifying a message against a signature.
|
||||
PublicKey interface {
|
||||
Pemmer
|
||||
// This function can be used to verify a message against a provided signature
|
||||
// using the given hash function.
|
||||
Verify(message []byte, signature []byte, hash crypto.Hash) (bool, error)
|
||||
}
|
||||
// PublicKey is used by the different crypto implementations to provide the
|
||||
// same functionality like verifying a message against a signature.
|
||||
PublicKey interface {
|
||||
Pemmer
|
||||
// This function can be used to verify a message against a provided signature
|
||||
// using the given hash function.
|
||||
Verify(message []byte, signature []byte, hash crypto.Hash) (bool, error)
|
||||
}
|
||||
|
||||
// Pemmer is used by all crypto structures which need to be available
|
||||
// in the pem format. The result can then be written to any structure
|
||||
// implementing the io.Writer interface.
|
||||
Pemmer interface {
|
||||
MarshalPem() (io.WriterTo, error)
|
||||
}
|
||||
// Pemmer is used by all crypto structures which need to be available
|
||||
// in the pem format. The result can then be written to any structure
|
||||
// implementing the io.Writer interface.
|
||||
Pemmer interface {
|
||||
MarshalPem() (io.WriterTo, error)
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue