0
0
Fork 0

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:
Gibheer 2015-03-25 20:36:21 +01:00
parent b3f621a312
commit 301d931ad7
7 changed files with 359 additions and 287 deletions

View File

@ -1,83 +1,87 @@
package pki package pki
import ( import (
"crypto/rand" "crypto/rand"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"math/big" "math/big"
"net" "net"
"time" "time"
) )
// labels used in the pem file format to mark certificate sign requests and certificates // labels used in the pem file format to mark certificate sign requests and certificates
const ( const (
PemLabelCertificateRequest = "CERTIFICATE REQUEST" PemLabelCertificateRequest = "CERTIFICATE REQUEST"
PemLabelCertificate = "CERTIFICATE" PemLabelCertificate = "CERTIFICATE"
) )
type ( type (
// Use CertificateData to fill in the minimum data you need to create a certificate // Use CertificateData to fill in the minimum data you need to create a certificate
// sign request. // sign request.
CertificateData struct { CertificateData struct {
Subject pkix.Name Subject pkix.Name
DNSNames []string DNSNames []string
EmailAddresses []string EmailAddresses []string
IPAddresses []net.IP IPAddresses []net.IP
} }
// Certificate is an alias on the x509.Certificate to add some methods. // Certificate is an alias on the x509.Certificate to add some methods.
Certificate x509.Certificate Certificate x509.Certificate
// CertificateRequest is an alias on the x509.CertificateRequest to add some methods. // CertificateRequest is an alias on the x509.CertificateRequest to add some methods.
CertificateRequest x509.CertificateRequest CertificateRequest x509.CertificateRequest
// CertificateOptions is used to provide the necessary information to create // CertificateOptions is used to provide the necessary information to create
// a certificate from a certificate sign request. // a certificate from a certificate sign request.
CertificateOptions struct { CertificateOptions struct {
SerialNumber *big.Int SerialNumber *big.Int
NotBefore time.Time NotBefore time.Time
NotAfter time.Time // Validity bounds. NotAfter time.Time // Validity bounds.
IsCA bool IsCA bool
// how many sub ca are allowed between this ca and the end/final certificate // how many sub ca are allowed between this ca and the end/final certificate
// if it is -1, then no limit will be set // if it is -1, then no limit will be set
CALength int CALength int
KeyUsage x509.KeyUsage KeyUsage x509.KeyUsage
} }
) )
// Create a new set of certificate data. // Create a new set of certificate data.
func NewCertificateData() *CertificateData { 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 // Create a certificate sign request from the input data and the private key of
// the request creator. // the request creator.
func (c *CertificateData) ToCertificateRequest(private_key PrivateKey) (*CertificateRequest, error) { func (c *CertificateData) ToCertificateRequest(private_key PrivateKey) (*CertificateRequest, error) {
csr := &x509.CertificateRequest{} csr := &x509.CertificateRequest{}
csr.Subject = c.Subject csr.Subject = c.Subject
csr.DNSNames = c.DNSNames csr.DNSNames = c.DNSNames
csr.IPAddresses = c.IPAddresses csr.IPAddresses = c.IPAddresses
csr.EmailAddresses = c.EmailAddresses csr.EmailAddresses = c.EmailAddresses
csr_asn1, err := x509.CreateCertificateRequest(rand.Reader, csr, private_key.PrivateKey()) csr_asn1, err := x509.CreateCertificateRequest(rand.Reader, csr, private_key.PrivateKey())
if err != nil { return nil, err } if err != nil {
return LoadCertificateSignRequest(csr_asn1) return nil, err
}
return LoadCertificateSignRequest(csr_asn1)
} }
// Load a certificate sign request from its asn1 representation. // Load a certificate sign request from its asn1 representation.
func LoadCertificateSignRequest(raw []byte) (*CertificateRequest, error) { func LoadCertificateSignRequest(raw []byte) (*CertificateRequest, error) {
csr, err := x509.ParseCertificateRequest(raw) csr, err := x509.ParseCertificateRequest(raw)
if err != nil { return nil, err } if err != nil {
return (*CertificateRequest)(csr), nil return nil, err
}
return (*CertificateRequest)(csr), nil
} }
// Return the certificate sign request as a pem block. // Return the certificate sign request as a pem block.
func (c *CertificateRequest) MarshalPem() (marshalledPemBlock, error) { func (c *CertificateRequest) MarshalPem() (marshalledPemBlock, error) {
block := &pem.Block{Type: PemLabelCertificateRequest, Bytes: c.Raw} block := &pem.Block{Type: PemLabelCertificateRequest, Bytes: c.Raw}
return pem.EncodeToMemory(block), nil return pem.EncodeToMemory(block), nil
} }
// Convert the certificate sign request to a certificate using the private key // 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. // Please also see the certificate options struct for information on mandatory fields.
// For more information, please read http://golang.org/pkg/crypto/x509/#CreateCertificate // For more information, please read http://golang.org/pkg/crypto/x509/#CreateCertificate
func (c *CertificateRequest) ToCertificate(private_key PrivateKey, 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 := &x509.Certificate{}
template.Subject = c.Subject template.Subject = c.Subject
template.DNSNames = c.DNSNames template.DNSNames = c.DNSNames
template.IPAddresses = c.IPAddresses template.IPAddresses = c.IPAddresses
template.EmailAddresses = c.EmailAddresses template.EmailAddresses = c.EmailAddresses
// if no ca is given, we have to set IsCA to self sign // if no ca is given, we have to set IsCA to self sign
if ca == nil { if ca == nil {
template.IsCA = true template.IsCA = true
} }
template.NotBefore = cert_opts.NotBefore template.NotBefore = cert_opts.NotBefore
template.NotAfter = cert_opts.NotAfter template.NotAfter = cert_opts.NotAfter
template.KeyUsage = cert_opts.KeyUsage template.KeyUsage = cert_opts.KeyUsage
template.IsCA = cert_opts.IsCA template.IsCA = cert_opts.IsCA
if cert_opts.IsCA { if cert_opts.IsCA {
template.BasicConstraintsValid = true template.BasicConstraintsValid = true
} }
if cert_opts.CALength >= 0 { if cert_opts.CALength >= 0 {
template.MaxPathLen = cert_opts.CALength template.MaxPathLen = cert_opts.CALength
template.MaxPathLenZero = true template.MaxPathLenZero = true
template.BasicConstraintsValid = true template.BasicConstraintsValid = true
} }
template.SerialNumber = cert_opts.SerialNumber template.SerialNumber = cert_opts.SerialNumber
var cert_asn1 []byte var cert_asn1 []byte
var err error var err error
// if we have no ca which can sign the cert, a self signed cert is wanted // 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) // (or isn't it? Maybe we should split creation of the template? But that would be ugly)
if ca == nil { if ca == nil {
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, template, c.PublicKey, private_key.PrivateKey()) cert_asn1, err = x509.CreateCertificate(rand.Reader, template, template, c.PublicKey, private_key.PrivateKey())
} else { } else {
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, (*x509.Certificate)(ca), c.PublicKey, private_key.PrivateKey()) cert_asn1, err = x509.CreateCertificate(rand.Reader, template, (*x509.Certificate)(ca), c.PublicKey, private_key.PrivateKey())
} }
if err != nil { return nil, err } if err != nil {
return LoadCertificate(cert_asn1) return nil, err
}
return LoadCertificate(cert_asn1)
} }
// Load a certificate from its asn1 representation. // Load a certificate from its asn1 representation.
func LoadCertificate(raw []byte) (*Certificate, error) { func LoadCertificate(raw []byte) (*Certificate, error) {
cert, err := x509.ParseCertificate(raw) cert, err := x509.ParseCertificate(raw)
if err != nil { return nil, err } if err != nil {
return (*Certificate)(cert), nil return nil, err
}
return (*Certificate)(cert), nil
} }
// marshal the certificate to a pem block // marshal the certificate to a pem block
func (c *Certificate) MarshalPem() (marshalledPemBlock, error) { func (c *Certificate) MarshalPem() (marshalledPemBlock, error) {
block := &pem.Block{Type: PemLabelCertificate, Bytes: c.Raw} block := &pem.Block{Type: PemLabelCertificate, Bytes: c.Raw}
return pem.EncodeToMemory(block), nil return pem.EncodeToMemory(block), nil
} }
// Check if the certificate options have the required fields set. // Check if the certificate options have the required fields set.
func (co *CertificateOptions) Valid() error { func (co *CertificateOptions) Valid() error {
if co.SerialNumber == nil { return fmt.Errorf("No serial number set!") } if co.SerialNumber == nil {
return nil return fmt.Errorf("No serial number set!")
}
return nil
} }

View File

@ -1,46 +1,61 @@
package pki package pki
import ( import (
"crypto/elliptic" "crypto/elliptic"
// "crypto/x509" "crypto/x509/pkix"
"crypto/x509/pkix" "math/big"
"math/big" "reflect"
"reflect" "testing"
"testing"
) )
var ( var (
TestCertificateData = CertificateData{ TestCertificateData = CertificateData{
Subject: pkix.Name{CommonName: "foobar"}, Subject: pkix.Name{CommonName: "foobar"},
DNSNames: []string{"foo.bar", "example.com"}, DNSNames: []string{"foo.bar", "example.com"},
} }
) )
func TestCertificateCreation(t *testing.T) { func TestCertificateCreation(t *testing.T) {
pk, err := NewPrivateKeyEcdsa(elliptic.P224()) pk, err := NewPrivateKeyEcdsa(elliptic.P224())
if err != nil { t.Errorf("cert: creating private key failed: %s", err) } if err != nil {
t.Errorf("cert: creating private key failed: %s", err)
}
csr, err := TestCertificateData.ToCertificateRequest(pk) csr, err := TestCertificateData.ToCertificateRequest(pk)
if err != nil { t.Errorf("cert: creating csr failed: %s", err) } if err != nil {
t.Errorf("cert: creating csr failed: %s", err)
}
cert_opts := CertificateOptions{ cert_opts := CertificateOptions{
// KeyUsage: x509.KeyUsageEncipherOnly | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign, // KeyUsage: x509.KeyUsageEncipherOnly | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
SerialNumber: big.NewInt(1), SerialNumber: big.NewInt(1),
} }
cert, err := csr.ToCertificate(pk, cert_opts, nil) cert, err := csr.ToCertificate(pk, cert_opts, nil)
if err != nil { t.Errorf("cert: creating cert failed: %s", err) } if err != nil {
t.Errorf("cert: creating cert failed: %s", err)
}
if !fieldsAreSame(TestCertificateData, cert) { if !fieldsAreSame(TestCertificateData, cert) {
t.Errorf("cert: Fields are not the same") t.Errorf("cert: Fields are not the same")
} }
} }
func fieldsAreSame(data CertificateData, cert *Certificate) bool { func fieldsAreSame(data CertificateData, cert *Certificate) bool {
if data.Subject.CommonName != cert.Subject.CommonName { return false } if data.Subject.CommonName != cert.Subject.CommonName {
if !reflect.DeepEqual(data.Subject.Country, cert.Subject.Country) { return false } return false
if !reflect.DeepEqual(data.DNSNames, cert.DNSNames) { return false } }
if !reflect.DeepEqual(data.IPAddresses, cert.IPAddresses) { return false } if !reflect.DeepEqual(data.Subject.Country, cert.Subject.Country) {
if !reflect.DeepEqual(data.EmailAddresses, cert.EmailAddresses) { return false } return false
return true }
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
View File

@ -1,112 +1,126 @@
package pki package pki
import ( import (
"crypto" "crypto"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/x509" "crypto/x509"
"encoding/asn1" "encoding/asn1"
"encoding/pem" "encoding/pem"
"errors" "errors"
"io" "io"
"math/big" "math/big"
) )
// This label is used as the type in the pem encoding of ECDSA private keys. // This label is used as the type in the pem encoding of ECDSA private keys.
const PemLabelEcdsa = "EC PRIVATE KEY" const PemLabelEcdsa = "EC PRIVATE KEY"
type ( type (
// This type handles the function calls to the ecdsa private key by // This type handles the function calls to the ecdsa private key by
// implementing the interface. // implementing the interface.
EcdsaPrivateKey struct { EcdsaPrivateKey struct {
private_key *ecdsa.PrivateKey private_key *ecdsa.PrivateKey
} }
// EcdsaPublicKey is the specific public key type for ecdsa. It implements the // EcdsaPublicKey is the specific public key type for ecdsa. It implements the
// the PublicKey interface. // the PublicKey interface.
EcdsaPublicKey struct { EcdsaPublicKey struct {
public_key *ecdsa.PublicKey public_key *ecdsa.PublicKey
} }
// This struct is used to marshal and parse the ecdsa signature. // This struct is used to marshal and parse the ecdsa signature.
signatureEcdsa struct { signatureEcdsa struct {
R, S *big.Int R, S *big.Int
} }
) )
// Create a new ECDSA private key using the specified curve. // Create a new ECDSA private key using the specified curve.
// For available curves, please take a look at the crypto/elliptic package. // For available curves, please take a look at the crypto/elliptic package.
func NewPrivateKeyEcdsa(curve elliptic.Curve) (*EcdsaPrivateKey, error) { func NewPrivateKeyEcdsa(curve elliptic.Curve) (*EcdsaPrivateKey, error) {
key, err := ecdsa.GenerateKey(curve, rand.Reader) key, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil { return nil, err } if err != nil {
return &EcdsaPrivateKey{key}, nil return nil, err
}
return &EcdsaPrivateKey{key}, nil
} }
// Load the private key from the asn1 representation. // Load the private key from the asn1 representation.
func LoadPrivateKeyEcdsa(raw []byte) (*EcdsaPrivateKey, error) { func LoadPrivateKeyEcdsa(raw []byte) (*EcdsaPrivateKey, error) {
key, err := x509.ParseECPrivateKey(raw) key, err := x509.ParseECPrivateKey(raw)
if err != nil { return nil, err } if err != nil {
return &EcdsaPrivateKey{key}, nil return nil, err
}
return &EcdsaPrivateKey{key}, nil
} }
// Create a new public key from the private key. // Create a new public key from the private key.
func (pr EcdsaPrivateKey) Public() PublicKey { 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. // Sign a message using the private key and the provided hash function.
func (pr EcdsaPrivateKey) Sign(message []byte, hash crypto.Hash) ([]byte, error) { func (pr EcdsaPrivateKey) Sign(message []byte, hash crypto.Hash) ([]byte, error) {
empty := make([]byte, 0) empty := make([]byte, 0)
if !hash.Available() { if !hash.Available() {
return empty, errors.New("Hash method is not available!") return empty, errors.New("Hash method is not available!")
} }
hashed_message := hash.New() hashed_message := hash.New()
hashed_message.Write(message) hashed_message.Write(message)
return pr.private_key.Sign(rand.Reader, hashed_message.Sum(nil), hash) return pr.private_key.Sign(rand.Reader, hashed_message.Sum(nil), hash)
} }
// This function returns the crypto.PrivateKey structure of the ECDSA key. // This function returns the crypto.PrivateKey structure of the ECDSA key.
func (pr EcdsaPrivateKey) PrivateKey() crypto.PrivateKey { 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 // This function implements the Pemmer interface to marshal the private key
// into a pem block. // into a pem block.
func (pr EcdsaPrivateKey) MarshalPem() (io.WriterTo, error) { func (pr EcdsaPrivateKey) MarshalPem() (io.WriterTo, error) {
asn1, err := x509.MarshalECPrivateKey(pr.private_key) asn1, err := x509.MarshalECPrivateKey(pr.private_key)
if err != nil { return nil, err } if err != nil {
pem_block := pem.Block{Type: PemLabelEcdsa, Bytes: asn1} return nil, err
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil }
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. // This functoin loads an ecdsa public key from the asn.1 representation.
func LoadPublicKeyEcdsa(raw []byte) (*EcdsaPublicKey, error) { func LoadPublicKeyEcdsa(raw []byte) (*EcdsaPublicKey, error) {
raw_pub, err := x509.ParsePKIXPublicKey(raw) raw_pub, err := x509.ParsePKIXPublicKey(raw)
if err != nil { return nil, err } if err != nil {
return nil, err
}
pub, ok := raw_pub.(*ecdsa.PublicKey) pub, ok := raw_pub.(*ecdsa.PublicKey)
if !ok { return nil, errors.New("Not an ecdsa key!") } if !ok {
return &EcdsaPublicKey{pub}, nil return nil, errors.New("Not an ecdsa key!")
}
return &EcdsaPublicKey{pub}, nil
} }
// This function implements the Pemmer interface to marshal the public key into // This function implements the Pemmer interface to marshal the public key into
// a pem block. // a pem block.
func (pu *EcdsaPublicKey) MarshalPem() (io.WriterTo, error) { func (pu *EcdsaPublicKey) MarshalPem() (io.WriterTo, error) {
asn1, err := x509.MarshalPKIXPublicKey(pu.public_key) asn1, err := x509.MarshalPKIXPublicKey(pu.public_key)
if err != nil { return nil, err } if err != nil {
pem_block := pem.Block{Type: PemLabelPublic, Bytes: asn1} return nil, err
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil }
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 // This function verifies a message using the public key, signature and hash
// function. // function.
// The hash function must be the same as was used to create the signature. // 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) { func (pu *EcdsaPublicKey) Verify(message []byte, signature_raw []byte, hash crypto.Hash) (bool, error) {
var sig signatureEcdsa var sig signatureEcdsa
_, err := asn1.Unmarshal(signature_raw, &sig) _, err := asn1.Unmarshal(signature_raw, &sig)
if err != nil { return false, err } if err != nil {
hashed_message := hash.New() return false, err
hashed_message.Write(message) }
return ecdsa.Verify(pu.public_key, hashed_message.Sum(nil), sig.R, sig.S), nil hashed_message := hash.New()
hashed_message.Write(message)
return ecdsa.Verify(pu.public_key, hashed_message.Sum(nil), sig.R, sig.S), nil
} }

View File

@ -1,16 +1,16 @@
package pki package pki
import ( import (
"io" "io"
) )
type ( type (
marshalledPemBlock []byte marshalledPemBlock []byte
) )
// This function writes the marshalled pem block to a writer and returns the // This function writes the marshalled pem block to a writer and returns the
// number of written bytes and eventual errors. // number of written bytes and eventual errors.
func (b marshalledPemBlock) WriteTo(stream io.Writer) (int64, error) { func (b marshalledPemBlock) WriteTo(stream io.Writer) (int64, error) {
numBytes, err := stream.Write(b) numBytes, err := stream.Write(b)
return int64(numBytes), err return int64(numBytes), err
} }

View File

@ -1,84 +1,109 @@
package pki package pki
import ( import (
"crypto" "crypto"
"crypto/elliptic" "crypto/elliptic"
"encoding/pem" "encoding/pem"
"testing" "testing"
) )
var ( var (
SignatureMessage = []byte("foobar") SignatureMessage = []byte("foobar")
SignatureHash = crypto.SHA512 SignatureHash = crypto.SHA512
) )
type ( type (
Loader func(raw []byte) (PublicKey, error) Loader func(raw []byte) (PublicKey, error)
) )
// run the marshal test // run the marshal test
func RunMarshalTest(pkType string, pe Pemmer, label string, t *testing.T) ([]byte, error) { func RunMarshalTest(pkType string, pe Pemmer, label string, t *testing.T) ([]byte, error) {
marshPem, err := pe.MarshalPem() marshPem, err := pe.MarshalPem()
if err != nil { if err != nil {
t.Errorf("%s: marshal pem not working: %s", pkType, err) t.Errorf("%s: marshal pem not working: %s", pkType, err)
return nil, err return nil, err
} }
block, _ := pem.Decode(marshPem) block, _ := pem.Decode(marshPem)
if block.Type != label { if block.Type != label {
t.Errorf("%s: marshalled pem wrong: %s", pkType, err) t.Errorf("%s: marshalled pem wrong: %s", pkType, err)
return nil, err return nil, err
} }
return block.Bytes, nil return block.Bytes, nil
} }
// test other private key functions // test other private key functions
func RunPrivateKeyTests(pkType string, pk PrivateKey, pu PublicKey, t *testing.T) { func RunPrivateKeyTests(pkType string, pk PrivateKey, pu PublicKey, t *testing.T) {
signature, err := pk.Sign(SignatureMessage, SignatureHash) signature, err := pk.Sign(SignatureMessage, SignatureHash)
if err != nil { t.Errorf("%s: error creating a signature: %s", pkType, err) } if err != nil {
t.Errorf("%s: error creating a signature: %s", pkType, err)
}
valid, err := pu.Verify(SignatureMessage, signature, SignatureHash) valid, err := pu.Verify(SignatureMessage, signature, SignatureHash)
if err != nil { t.Errorf("%s: could not verify message: %s", pkType, err) } if err != nil {
if !valid { t.Errorf("%s: signature invalid, but should be valid!", pkType) } 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 // test ecdsa private key functions
func TestEcdsaFunctions(t *testing.T) { func TestEcdsaFunctions(t *testing.T) {
pk, err := NewPrivateKeyEcdsa(elliptic.P521()) pk, err := NewPrivateKeyEcdsa(elliptic.P521())
if err != nil { t.Errorf("ecdsa: creating private key failed: %s", err) } if err != nil {
t.Errorf("ecdsa: creating private key failed: %s", err)
}
blockBytes, err := RunMarshalTest("ecdsa", pk, PemLabelEcdsa, t) blockBytes, err := RunMarshalTest("ecdsa", pk, PemLabelEcdsa, t)
if err != nil { return } if err != nil {
return
}
pk, err = LoadPrivateKeyEcdsa(blockBytes) pk, err = LoadPrivateKeyEcdsa(blockBytes)
if err != nil { t.Errorf("ecdsa: pem content wrong: %s", err) } if err != nil {
t.Errorf("ecdsa: pem content wrong: %s", err)
}
blockBytes, err = RunMarshalTest("ecdsa-public", pk.Public(), PemLabelPublic, t) blockBytes, err = RunMarshalTest("ecdsa-public", pk.Public(), PemLabelPublic, t)
if err != nil { return } if err != nil {
return
}
pu, err := LoadPublicKeyEcdsa(blockBytes) pu, err := LoadPublicKeyEcdsa(blockBytes)
if err != nil { t.Errorf("ecdsa-public: pem content wrong: %s", err) } 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 // test rsa private key functions
func TestRsaFunctions(t *testing.T) { func TestRsaFunctions(t *testing.T) {
pk, err := NewPrivateKeyRsa(2048) pk, err := NewPrivateKeyRsa(2048)
if err != nil { t.Errorf("rsa: creating private key failed: %s", err) } if err != nil {
t.Errorf("rsa: creating private key failed: %s", err)
}
blockBytes, err := RunMarshalTest("rsa", pk, PemLabelRsa, t) blockBytes, err := RunMarshalTest("rsa", pk, PemLabelRsa, t)
if err != nil { return } if err != nil {
return
}
pk, err = LoadPrivateKeyRsa(blockBytes) pk, err = LoadPrivateKeyRsa(blockBytes)
if err != nil { t.Errorf("rsa: pem content wrong: %s", err) } 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) pu, err := LoadPublicKeyRsa(blockBytes)
if err != nil { return } if err != nil {
t.Errorf("rsa-public: pem content wrong: %s", err)
}
pu, err := LoadPublicKeyRsa(blockBytes) RunPrivateKeyTests("rsa", pk, pu, t)
if err != nil { t.Errorf("rsa-public: pem content wrong: %s", err) }
RunPrivateKeyTests("rsa", pk, pu, t)
} }

70
rsa.go
View File

@ -1,76 +1,82 @@
package pki package pki
import ( import (
"crypto" "crypto"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"errors" "errors"
"io" "io"
) )
const ( const (
PemLabelRsa = "RSA PRIVATE KEY" PemLabelRsa = "RSA PRIVATE KEY"
) )
type ( type (
RsaPrivateKey struct { RsaPrivateKey struct {
private_key *rsa.PrivateKey private_key *rsa.PrivateKey
} }
RsaPublicKey struct { RsaPublicKey struct {
public_key *rsa.PublicKey public_key *rsa.PublicKey
} }
) )
// generate a new rsa private key // generate a new rsa private key
func NewPrivateKeyRsa(size int) (*RsaPrivateKey, error) { func NewPrivateKeyRsa(size int) (*RsaPrivateKey, error) {
key, err := rsa.GenerateKey(rand.Reader, size) key, err := rsa.GenerateKey(rand.Reader, size)
if err != nil { return nil, err } if err != nil {
return &RsaPrivateKey{key}, nil return nil, err
}
return &RsaPrivateKey{key}, nil
} }
// load a rsa private key its ASN.1 presentation // load a rsa private key its ASN.1 presentation
func LoadPrivateKeyRsa(raw []byte) (*RsaPrivateKey, error) { func LoadPrivateKeyRsa(raw []byte) (*RsaPrivateKey, error) {
key, err := x509.ParsePKCS1PrivateKey(raw) key, err := x509.ParsePKCS1PrivateKey(raw)
if err != nil { return nil, err } if err != nil {
return &RsaPrivateKey{key}, nil return nil, err
}
return &RsaPrivateKey{key}, nil
} }
func (pr *RsaPrivateKey) Public() PublicKey { 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) { 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 // get the private key
func (pr RsaPrivateKey) PrivateKey() crypto.PrivateKey { func (pr RsaPrivateKey) PrivateKey() crypto.PrivateKey {
return pr.private_key return pr.private_key
} }
func (pr RsaPrivateKey) MarshalPem() (io.WriterTo, error) { func (pr RsaPrivateKey) MarshalPem() (io.WriterTo, error) {
asn1 := x509.MarshalPKCS1PrivateKey(pr.private_key) asn1 := x509.MarshalPKCS1PrivateKey(pr.private_key)
pem_block := pem.Block{Type: PemLabelRsa, Bytes: asn1} pem_block := pem.Block{Type: PemLabelRsa, Bytes: asn1}
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
} }
// restore a rsa public key // restore a rsa public key
func LoadPublicKeyRsa(raw []byte) (*RsaPublicKey, error) { 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 // marshal a rsa public key into pem format
func (pu *RsaPublicKey) MarshalPem() (io.WriterTo, error) { func (pu *RsaPublicKey) MarshalPem() (io.WriterTo, error) {
asn1, err := x509.MarshalPKIXPublicKey(pu.public_key) asn1, err := x509.MarshalPKIXPublicKey(pu.public_key)
if err != nil { return nil, err } if err != nil {
pem_block := pem.Block{Type: PemLabelPublic, Bytes: asn1} return nil, err
return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil }
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 // verify a message with a signature using the public key
func (pu *RsaPublicKey) Verify(message []byte, signature []byte, hash crypto.Hash) (bool, error) { 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!")
} }

View File

@ -15,41 +15,41 @@
package pki package pki
import ( import (
"crypto" "crypto"
"io" "io"
) )
// This label is used as the type in the pem encoding of public keys. // This label is used as the type in the pem encoding of public keys.
const PemLabelPublic = "PUBLIC KEY" const PemLabelPublic = "PUBLIC KEY"
type ( type (
// PrivateKey is a common interface for all crypto implementations to provide // PrivateKey is a common interface for all crypto implementations to provide
// the same functions, like deriving a public key or signing a message. // the same functions, like deriving a public key or signing a message.
PrivateKey interface { PrivateKey interface {
// Derive a new public key from the private key. // Derive a new public key from the private key.
Public() PublicKey Public() PublicKey
// Sign a message using the public key and the given hash method. // Sign a message using the public key and the given hash method.
// To use a hash method, include the package // To use a hash method, include the package
// import _ "crypto/sha512" // import _ "crypto/sha512"
Sign(message []byte, hash crypto.Hash) ([]byte, error) Sign(message []byte, hash crypto.Hash) ([]byte, error)
// Return the original go structure of the private key. // Return the original go structure of the private key.
PrivateKey() crypto.PrivateKey PrivateKey() crypto.PrivateKey
} }
// PublicKey is used by the different crypto implementations to provide the // PublicKey is used by the different crypto implementations to provide the
// same functionality like verifying a message against a signature. // same functionality like verifying a message against a signature.
PublicKey interface { PublicKey interface {
Pemmer Pemmer
// This function can be used to verify a message against a provided signature // This function can be used to verify a message against a provided signature
// using the given hash function. // using the given hash function.
Verify(message []byte, signature []byte, hash crypto.Hash) (bool, error) Verify(message []byte, signature []byte, hash crypto.Hash) (bool, error)
} }
// Pemmer is used by all crypto structures which need to be available // 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 // in the pem format. The result can then be written to any structure
// implementing the io.Writer interface. // implementing the io.Writer interface.
Pemmer interface { Pemmer interface {
MarshalPem() (io.WriterTo, error) MarshalPem() (io.WriterTo, error)
} }
) )