mirror of
https://github.com/gregtwallace/apc-p15-tool.git
synced 2025-01-22 08:14:08 +00:00
cert: finish p15 creation
This commit is contained in:
parent
1f6dad4907
commit
a626d84fdb
2 changed files with 195 additions and 22 deletions
|
@ -3,31 +3,33 @@ package pkcs15
|
||||||
import (
|
import (
|
||||||
"apc-p15-tool/pkg/tools/asn1obj"
|
"apc-p15-tool/pkg/tools/asn1obj"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/asn1"
|
"encoding/binary"
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
// keyId returns the keyId for the overall key object
|
// keyId returns the keyId for the overall key object
|
||||||
func (p15 *pkcs15KeyCert) keyId() []byte {
|
func (p15 *pkcs15KeyCert) keyId() []byte {
|
||||||
|
// object to hash is just the RawSubjectPublicKeyInfo
|
||||||
|
|
||||||
// Create Object to hash
|
// Create Object to hash
|
||||||
hashObj := asn1obj.Sequence([][]byte{
|
// hashObj := asn1obj.Sequence([][]byte{
|
||||||
asn1obj.Sequence([][]byte{
|
// asn1obj.Sequence([][]byte{
|
||||||
// Key is RSA
|
// // Key is RSA
|
||||||
asn1obj.ObjectIdentifier(asn1obj.OIDrsaEncryptionPKCS1),
|
// asn1obj.ObjectIdentifier(asn1obj.OIDrsaEncryptionPKCS1),
|
||||||
asn1.NullBytes,
|
// asn1.NullBytes,
|
||||||
}),
|
// }),
|
||||||
// BIT STRING of rsa key public key
|
// // BIT STRING of rsa key public key
|
||||||
asn1obj.BitString(
|
// asn1obj.BitString(
|
||||||
asn1obj.Sequence([][]byte{
|
// asn1obj.Sequence([][]byte{
|
||||||
asn1obj.Integer(p15.key.N),
|
// asn1obj.Integer(p15.key.N),
|
||||||
asn1obj.Integer((big.NewInt(int64(p15.key.E)))),
|
// asn1obj.Integer((big.NewInt(int64(p15.key.E)))),
|
||||||
}),
|
// }),
|
||||||
),
|
// ),
|
||||||
})
|
// })
|
||||||
|
|
||||||
// SHA-1 Hash
|
// SHA-1 Hash
|
||||||
hasher := sha1.New()
|
hasher := sha1.New()
|
||||||
_, err := hasher.Write(hashObj)
|
_, err := hasher.Write(p15.cert.RawSubjectPublicKeyInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -50,3 +52,163 @@ func (p15 *pkcs15KeyCert) keyIdInt2() []byte {
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keyIdInt3 returns the sequence for keyId with INT val of 3; This value is equivelant
|
||||||
|
// to "issuerAndSerialNumberHash" and rfc defines IssuerAndSerialNumber SEQUENCE:
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc3852#section-10.2.4
|
||||||
|
func (p15 *pkcs15KeyCert) keyIdInt3() []byte {
|
||||||
|
// object to hash
|
||||||
|
hashObj := asn1obj.Sequence([][]byte{
|
||||||
|
// issuerDistinguishedName
|
||||||
|
p15.cert.RawIssuer,
|
||||||
|
// serialNumber
|
||||||
|
asn1obj.Integer(p15.cert.SerialNumber),
|
||||||
|
})
|
||||||
|
|
||||||
|
// SHA-1 Hash
|
||||||
|
hasher := sha1.New()
|
||||||
|
_, err := hasher.Write(hashObj)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// object to return
|
||||||
|
obj := asn1obj.Sequence([][]byte{
|
||||||
|
asn1obj.Integer(big.NewInt(3)),
|
||||||
|
asn1obj.OctetString(hasher.Sum(nil)),
|
||||||
|
})
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyIdInt6 returns the sequence for keyId with INT val of 6; This value is equivelant
|
||||||
|
// to "issuerNameHash"
|
||||||
|
func (p15 *pkcs15KeyCert) keyIdInt6() []byte {
|
||||||
|
// object to hash is just the RawIssuer
|
||||||
|
|
||||||
|
// SHA-1 Hash
|
||||||
|
hasher := sha1.New()
|
||||||
|
_, err := hasher.Write(p15.cert.RawIssuer)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// object to return
|
||||||
|
obj := asn1obj.Sequence([][]byte{
|
||||||
|
asn1obj.Integer(big.NewInt(6)),
|
||||||
|
asn1obj.OctetString(hasher.Sum(nil)),
|
||||||
|
})
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyIdInt7 returns the sequence for keyId with INT val of 7; This value is equivelant
|
||||||
|
// to "subjectNameHash"
|
||||||
|
func (p15 *pkcs15KeyCert) keyIdInt7() []byte {
|
||||||
|
// object to hash is just the RawIssuer
|
||||||
|
|
||||||
|
// SHA-1 Hash
|
||||||
|
hasher := sha1.New()
|
||||||
|
_, err := hasher.Write(p15.cert.RawSubject)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// object to return
|
||||||
|
obj := asn1obj.Sequence([][]byte{
|
||||||
|
asn1obj.Integer(big.NewInt(7)),
|
||||||
|
asn1obj.OctetString(hasher.Sum(nil)),
|
||||||
|
})
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyIdInt8 returns the sequence for keyId with INT val of 8; This value is equivelant
|
||||||
|
// to "pgp", which is PGP v3 key Id. This value is just the last 8 bytes of the public
|
||||||
|
// key N value
|
||||||
|
func (p15 *pkcs15KeyCert) keyIdInt8() []byte {
|
||||||
|
nBytes := p15.key.N.Bytes()
|
||||||
|
|
||||||
|
// object to return
|
||||||
|
obj := asn1obj.Sequence([][]byte{
|
||||||
|
asn1obj.Integer(big.NewInt(8)),
|
||||||
|
asn1obj.OctetString(nBytes[len(nBytes)-8:]),
|
||||||
|
})
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
// bigIntToMpi returns the MPI (as defined in RFC 4880 s 3.2) from a given
|
||||||
|
// big.Int; this is used as a helper for key ID 9 (openPGP)
|
||||||
|
func bigIntToMpi(i *big.Int) []byte {
|
||||||
|
length := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(length, uint16(i.BitLen()))
|
||||||
|
|
||||||
|
return append(length, i.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyIdInt9 returns the sequence for keyId with INT val of 9; This value is equivelant
|
||||||
|
// to "openPGP", which is PGP v4 key Id.
|
||||||
|
// see: https://www.rfc-editor.org/rfc/rfc4880.html s 12.2
|
||||||
|
func (p15 *pkcs15KeyCert) keyIdInt9() []byte {
|
||||||
|
// A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99,
|
||||||
|
// followed by the two-octet packet length, followed by the entire
|
||||||
|
// Public-Key packet starting with the version field. The Key ID is the
|
||||||
|
// low-order 64 bits of the fingerprint.
|
||||||
|
|
||||||
|
// the entire Public-Key packet
|
||||||
|
publicKeyPacket := []byte{}
|
||||||
|
|
||||||
|
// starting with the version field (A one-octet version number (4)).
|
||||||
|
publicKeyPacket = append(publicKeyPacket, byte(4))
|
||||||
|
|
||||||
|
// A four-octet number denoting the time that the key was created.
|
||||||
|
time := make([]byte, 4)
|
||||||
|
|
||||||
|
// NOTE: use cert validity start as proxy for key creation since key pem
|
||||||
|
// doesn't actually contain a created at time -- in reality notBefore tends
|
||||||
|
// to be ~ 1 hour ish BEFORE the cert was even created. Key would also
|
||||||
|
// obviously have to be created prior to the cert creation.
|
||||||
|
binary.BigEndian.PutUint32(time, uint32(p15.cert.NotBefore.Unix()))
|
||||||
|
publicKeyPacket = append(publicKeyPacket, time...)
|
||||||
|
|
||||||
|
// A one-octet number denoting the public-key algorithm of this key.
|
||||||
|
// 1 - RSA (Encrypt or Sign) [HAC]
|
||||||
|
publicKeyPacket = append(publicKeyPacket, byte(1))
|
||||||
|
|
||||||
|
// Algorithm-Specific Fields for RSA public keys:
|
||||||
|
// multiprecision integer (MPI) of RSA public modulus n
|
||||||
|
publicKeyPacket = append(publicKeyPacket, bigIntToMpi(p15.key.N)...)
|
||||||
|
|
||||||
|
// MPI of RSA public encryption exponent e
|
||||||
|
e := big.NewInt(int64(p15.key.PublicKey.E))
|
||||||
|
publicKeyPacket = append(publicKeyPacket, bigIntToMpi(e)...)
|
||||||
|
|
||||||
|
// Assemble the V4 byte array that will be hashed
|
||||||
|
// 0x99 (1 octet)
|
||||||
|
toHash := []byte{0x99}
|
||||||
|
|
||||||
|
// big endian encoded length of public key packet (2 octets)
|
||||||
|
length := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(length, uint16(len(publicKeyPacket)))
|
||||||
|
toHash = append(toHash, length...)
|
||||||
|
|
||||||
|
// Public-Key packet
|
||||||
|
toHash = append(toHash, publicKeyPacket...)
|
||||||
|
|
||||||
|
// SHA-1 Hash (Fingerprint)
|
||||||
|
hasher := sha1.New()
|
||||||
|
hasher.Write(toHash)
|
||||||
|
sha1Hash := hasher.Sum(nil)
|
||||||
|
|
||||||
|
// keyId is lower 64 bits (8 bytes)
|
||||||
|
keyId := sha1Hash[len(sha1Hash)-8:]
|
||||||
|
|
||||||
|
// object to return
|
||||||
|
obj := asn1obj.Sequence([][]byte{
|
||||||
|
asn1obj.Integer(big.NewInt(9)),
|
||||||
|
asn1obj.OctetString(keyId),
|
||||||
|
})
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
|
@ -101,7 +101,6 @@ func (p15 *pkcs15KeyCert) toP15PrivateKey() ([]byte, error) {
|
||||||
// NOTE: Do not use this to try and turn just a cert into a p15. I don't believe,
|
// NOTE: Do not use this to try and turn just a cert into a p15. I don't believe,
|
||||||
// such a thing is permissible under the spec.
|
// such a thing is permissible under the spec.
|
||||||
func (p15 *pkcs15KeyCert) toP15Cert() ([]byte, error) {
|
func (p15 *pkcs15KeyCert) toP15Cert() ([]byte, error) {
|
||||||
|
|
||||||
// cert object
|
// cert object
|
||||||
cert := asn1obj.Sequence([][]byte{
|
cert := asn1obj.Sequence([][]byte{
|
||||||
// commonObjectAttributes - Label
|
// commonObjectAttributes - Label
|
||||||
|
@ -114,11 +113,23 @@ func (p15 *pkcs15KeyCert) toP15Cert() ([]byte, error) {
|
||||||
// additional keyids
|
// additional keyids
|
||||||
asn1obj.ExplicitCompound(2, [][]byte{
|
asn1obj.ExplicitCompound(2, [][]byte{
|
||||||
p15.keyIdInt2(),
|
p15.keyIdInt2(),
|
||||||
// p15.keyIdInt3(),
|
p15.keyIdInt3(),
|
||||||
// p15.keyIdInt6(),
|
p15.keyIdInt6(),
|
||||||
// p15.keyIdInt7(),
|
p15.keyIdInt7(),
|
||||||
// p15.keyIdInt8(),
|
p15.keyIdInt8(),
|
||||||
// p15.keyIdInt9(),
|
p15.keyIdInt9(),
|
||||||
|
}),
|
||||||
|
// CommonKeyAttributes - startDate
|
||||||
|
asn1obj.GeneralizedTime(p15.cert.NotBefore),
|
||||||
|
// CommonKeyAttributes - [4] endDate
|
||||||
|
asn1obj.GeneralizedTimeExplicitValue(4, p15.cert.NotAfter),
|
||||||
|
}),
|
||||||
|
// actual certificate itself
|
||||||
|
asn1obj.ExplicitCompound(1, [][]byte{
|
||||||
|
asn1obj.Sequence([][]byte{
|
||||||
|
asn1obj.ExplicitCompound(0, [][]byte{
|
||||||
|
p15.cert.Raw,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue