mirror of
https://github.com/gregtwallace/apc-p15-tool.git
synced 2025-06-09 13:16:51 +00:00
app: restructure and start building p15 output
This commit is contained in:
parent
6610c92058
commit
e2e4f2037c
24 changed files with 622 additions and 168 deletions
35
pkg/pkcs15/keyid.go
Normal file
35
pkg/pkcs15/keyid.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package pkcs15
|
||||
|
||||
import (
|
||||
"apc-p15-tool/pkg/tools/asn1obj"
|
||||
"crypto/sha1"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// keyId returns the keyId for the overall key object
|
||||
func (p15 *pkcs15KeyCert) keyId() []byte {
|
||||
// Create Object to hash
|
||||
hashObj := asn1obj.Sequence([][]byte{
|
||||
asn1obj.Sequence([][]byte{
|
||||
// Key is RSA
|
||||
asn1obj.ObjectIdentifier(asn1obj.OIDrsaEncryptionPKCS1),
|
||||
asn1obj.Null(),
|
||||
}),
|
||||
// BIT STRING of rsa key public key
|
||||
asn1obj.BitString(
|
||||
asn1obj.Sequence([][]byte{
|
||||
asn1obj.Integer(p15.key.N),
|
||||
asn1obj.Integer((big.NewInt(int64(p15.key.E)))),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
// SHA-1 Hash
|
||||
hasher := sha1.New()
|
||||
_, err := hasher.Write(hashObj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return hasher.Sum(nil)
|
||||
}
|
66
pkg/pkcs15/marshal.go
Normal file
66
pkg/pkcs15/marshal.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
package pkcs15
|
||||
|
||||
import (
|
||||
"apc-p15-tool/pkg/tools/asn1obj"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const (
|
||||
apcKeyLabel = "Private key"
|
||||
)
|
||||
|
||||
// ToP15File turns the key and cert into a properly formatted and encoded
|
||||
// p15 file
|
||||
func (p15 *pkcs15KeyCert) ToP15File() ([]byte, error) {
|
||||
// private key object
|
||||
pkey, err := p15.toP15PrivateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ContentInfo
|
||||
p15File := asn1obj.Sequence([][]byte{
|
||||
|
||||
// contentType: OID: 1.2.840.113549.1.15.3.1 pkcs15content (PKCS #15 content type)
|
||||
asn1obj.ObjectIdentifier(asn1obj.OIDPkscs15Content),
|
||||
|
||||
// content
|
||||
asn1obj.Explicit(0,
|
||||
asn1obj.Sequence([][]byte{
|
||||
asn1obj.Integer(big.NewInt(0)),
|
||||
asn1obj.Sequence([][]byte{
|
||||
asn1obj.Explicit(0,
|
||||
asn1obj.Explicit(0,
|
||||
pkey,
|
||||
),
|
||||
),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
return p15File, nil
|
||||
}
|
||||
|
||||
// toP15PrivateKey creates the encoded private key. it is broken our from the larger p15
|
||||
// function for readability
|
||||
func (p15 *pkcs15KeyCert) toP15PrivateKey() ([]byte, error) {
|
||||
// key object
|
||||
key := asn1obj.Sequence([][]byte{
|
||||
// commonObjectAttributes - Label
|
||||
asn1obj.Sequence([][]byte{
|
||||
asn1obj.UTF8String(apcKeyLabel),
|
||||
}),
|
||||
// CommonKeyAttributes
|
||||
asn1obj.Sequence([][]byte{
|
||||
// CommonKeyAttributes - iD - uses keyId that is SHA1( SubjectPublicKeyInfo SEQUENCE )
|
||||
asn1obj.OctetString(p15.keyId()),
|
||||
// CommonKeyAttributes - usage (trailing 0s will drop)
|
||||
asn1obj.BitString([]byte{byte(0b11100010)}),
|
||||
// CommonKeyAttributes - accessFlags (trailing 0s will drop)
|
||||
asn1obj.BitString([]byte{byte(0b10110000)}),
|
||||
}),
|
||||
})
|
||||
|
||||
return key, nil
|
||||
}
|
1
pkg/pkcs15/oids.go
Normal file
1
pkg/pkcs15/oids.go
Normal file
|
@ -0,0 +1 @@
|
|||
package pkcs15
|
120
pkg/pkcs15/pem_decode.go
Normal file
120
pkg/pkcs15/pem_decode.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
package pkcs15
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
errPemKeyBadBlock = errors.New("pkcs15: pem key: failed to decode pem block")
|
||||
errPemKeyFailedToParse = errors.New("pkcs15: pem key: failed to parse key")
|
||||
errPemKeyWrongBlockType = errors.New("pkcs15: pem key: unsupported pem block type (only pkcs1 and pkcs8 supported)")
|
||||
errPemKeyWrongType = errors.New("pkcs15: pem key: unsupported key type (only rsa 2,048 supported)")
|
||||
|
||||
errPemCertBadBlock = errors.New("pkcs15: pem cert: failed to decode pem block")
|
||||
errPemCertFailedToParse = errors.New("pkcs15: pem cert: failed to parse cert")
|
||||
)
|
||||
|
||||
// pemKeyDecode attempts to decode a pem encoded byte slice and then attempts
|
||||
// to parse an RSA private key from the decoded pem block. an error is returned
|
||||
// if any of these steps fail OR if the rsa key is not of bitlen 2,048
|
||||
func pemKeyDecode(keyPem []byte) (*rsa.PrivateKey, error) {
|
||||
// decode
|
||||
pemBlock, _ := pem.Decode([]byte(keyPem))
|
||||
if pemBlock == nil {
|
||||
return nil, errPemKeyBadBlock
|
||||
}
|
||||
|
||||
// parsing depends on block type
|
||||
var rsaKey *rsa.PrivateKey
|
||||
|
||||
switch pemBlock.Type {
|
||||
case "RSA PRIVATE KEY": // PKCS1
|
||||
var err error
|
||||
|
||||
rsaKey, err = x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, errPemKeyFailedToParse
|
||||
}
|
||||
|
||||
// basic sanity check
|
||||
err = rsaKey.Validate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pkcs15: pem key: failed sanity check (%s)", err)
|
||||
}
|
||||
|
||||
// verify proper bitlen
|
||||
if rsaKey.N.BitLen() != 2048 {
|
||||
return nil, errPemKeyWrongType
|
||||
}
|
||||
|
||||
// good to go
|
||||
|
||||
case "PRIVATE KEY": // PKCS8
|
||||
pkcs8Key, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, errPemKeyFailedToParse
|
||||
}
|
||||
|
||||
switch pkcs8Key := pkcs8Key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
rsaKey = pkcs8Key
|
||||
|
||||
// basic sanity check
|
||||
err = rsaKey.Validate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pkcs15: pem key: failed sanity check (%s)", err)
|
||||
}
|
||||
|
||||
// verify proper bitlen
|
||||
if rsaKey.N.BitLen() != 2048 {
|
||||
return nil, errPemKeyWrongType
|
||||
}
|
||||
|
||||
// good to go
|
||||
|
||||
default:
|
||||
return nil, errPemKeyWrongType
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, errPemKeyWrongBlockType
|
||||
}
|
||||
|
||||
// if rsaKey is nil somehow, error
|
||||
if rsaKey == nil {
|
||||
return nil, errors.New("pkcs15: pem key: rsa key unexpectedly nil (report bug to project repo)")
|
||||
}
|
||||
|
||||
// success!
|
||||
return rsaKey, nil
|
||||
}
|
||||
|
||||
// pemCertDecode attempts to decode a pem encoded byte slice and then attempts
|
||||
// to parse a certificate from it. The certificate is also check against the
|
||||
// key that is passed in to verify the key matches the certificate.
|
||||
func pemCertDecode(certPem, keyPem []byte) (*x509.Certificate, error) {
|
||||
// verify key and cert make a valid key pair
|
||||
_, err := tls.X509KeyPair(certPem, keyPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// discard rest, apc tool only bundles end cert
|
||||
block, _ := pem.Decode(certPem)
|
||||
if block == nil || block.Type != "CERTIFICATE" {
|
||||
return nil, errPemCertBadBlock
|
||||
}
|
||||
|
||||
// Get the cert struct
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, errPemCertFailedToParse
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
36
pkg/pkcs15/pem_to_p15.go
Normal file
36
pkg/pkcs15/pem_to_p15.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package pkcs15
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
)
|
||||
|
||||
// pkcs15KeyCert holds the data for a key and certificate pair; it provides
|
||||
// various methods to transform pkcs15 data
|
||||
type pkcs15KeyCert struct {
|
||||
key *rsa.PrivateKey
|
||||
cert *x509.Certificate
|
||||
}
|
||||
|
||||
// ParsePEMToPKCS15 parses the provide pem files to a pkcs15 struct; it also does some
|
||||
// basic sanity check; if any of this fails, an error is returned
|
||||
func ParsePEMToPKCS15(keyPem, certPem []byte) (*pkcs15KeyCert, error) {
|
||||
// decode / check key
|
||||
key, err := pemKeyDecode(keyPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// decode / check cert
|
||||
cert, err := pemCertDecode(certPem, keyPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p15 := &pkcs15KeyCert{
|
||||
key: key,
|
||||
cert: cert,
|
||||
}
|
||||
|
||||
return p15, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue