1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
|
package tss2
import (
"encoding/asn1"
"errors"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
)
var (
oidLoadableKey = asn1.ObjectIdentifier{2, 23, 133, 10, 1, 3}
oidImportableKey = asn1.ObjectIdentifier{2, 23, 133, 10, 1, 4}
oidSealedKey = asn1.ObjectIdentifier{2, 23, 133, 10, 1, 5}
)
// TPMKey is defined in https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#section-3.1:
//
// TPMKey ::= SEQUENCE {
// type OBJECT IDENTIFIER,
// emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
// policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL,
// secret [2] EXPLICIT OCTET STRING OPTIONAL,
// authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL,
// parent INTEGER,
// pubkey OCTET STRING,
// privkey OCTET STRING
// }
type TPMKey struct {
Type asn1.ObjectIdentifier
EmptyAuth bool `asn1:"optional,explicit,tag:0"`
Policy []TPMPolicy `asn1:"optional,explicit,tag:1"`
Secret []byte `asn1:"optional,explicit,tag:2"`
AuthPolicy []TPMAuthPolicy `asn1:"optional,explicit,tag:3"`
Parent int
PublicKey []byte
PrivateKey []byte
}
// TPMPolicy is defined in https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#section-4.1:
//
// TPMPolicy ::= SEQUENCE {
// commandCode [0] EXPLICIT INTEGER,
// commandPolicy [1] EXPLICIT OCTET STRING
// }
type TPMPolicy struct {
CommandCode int `asn1:"explicit,tag:0"`
CommandPolicy []byte `asn1:"explicit,tag:1"`
}
// TPMAuthPolicy is defined in https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#section-5.1
//
// TPMAuthPolicy ::= SEQUENCE {
// name [0] EXPLICIT UTF8String OPTIONAL,
// policy [1] EXPLICIT SEQUENCE OF TPMPolicy
// }
type TPMAuthPolicy struct {
Name string `asn1:"utf8,optional,explicit,tag:0"`
Policy []TPMPolicy `asn1:"explicit,tag:1"`
}
// ParsePrivateKey parses a single TPM key from the given ASN.1 DER data.
//
// # Experimental
//
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
// release.
func ParsePrivateKey(derBytes []byte) (*TPMKey, error) {
var err error
input := cryptobyte.String(derBytes)
if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("malformed TSS2 key")
}
key := new(TPMKey)
if !input.ReadASN1ObjectIdentifier(&key.Type) {
return nil, errors.New("malformed TSS2 type")
}
if tag, ok := readOptionalTag(&input, 0); ok {
if !readASN1Boolean(&tag, &key.EmptyAuth) {
return nil, errors.New("malformed TSS2 emptyAuth")
}
}
// TODO(mariano): generate key with policy
if tag, ok := readOptionalTag(&input, 1); ok {
var policy cryptobyte.String
if !tag.ReadASN1(&policy, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("malformed TSS2 policy")
}
key.Policy, err = readTPMPolicySequence(&policy)
if err != nil {
return nil, err
}
}
// TODO(mariano): generate key with secret
if tag, ok := readOptionalTag(&input, 2); ok {
if key.Secret, ok = readOctetString(&tag); !ok {
return nil, errors.New("malformed TSS2 secret")
}
}
// TODO(mariano): generate key with authPolicy
if tag, ok := readOptionalTag(&input, 3); ok {
if key.AuthPolicy, err = readTPMAuthPolicy(&tag); err != nil {
return nil, err
}
}
if !input.ReadASN1Integer(&key.Parent) {
return nil, errors.New("malformed TSS2 parent")
}
var ok bool
if key.PublicKey, ok = readOctetString(&input); !ok {
return nil, errors.New("malformed TSS2 pubkey")
}
if key.PrivateKey, ok = readOctetString(&input); !ok {
return nil, errors.New("malformed TSS2 privkey")
}
return key, nil
}
// MarshalPrivateKey converts the given key to a TSS2 ASN.1 DER form.
//
// # Experimental
//
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
// release.
func MarshalPrivateKey(key *TPMKey) ([]byte, error) {
if key == nil {
return nil, errors.New("tpmKey cannot be nil")
}
return asn1.Marshal(*key)
}
func readOptionalTag(input *cryptobyte.String, tag uint8) (cryptobyte.String, bool) {
var isPresent bool
var output cryptobyte.String
if !input.ReadOptionalASN1(&output, &isPresent, cryptobyte_asn1.Tag(tag).Constructed().ContextSpecific()) {
return nil, false
}
return output, isPresent
}
func readOctetString(input *cryptobyte.String) ([]byte, bool) {
var os cryptobyte.String
if !input.ReadASN1(&os, cryptobyte_asn1.OCTET_STRING) {
return nil, false
}
return os, true
}
// readASN1Boolean accepts 0x01 as a TRUE value for a boolean type. OpenSSL
// seems to confuse DER with BER encoding and encodes the BOOLEAN TRUE as 0x01
// instead of 0xff.
func readASN1Boolean(input *cryptobyte.String, out *bool) bool {
var bytes cryptobyte.String
if !input.ReadASN1(&bytes, cryptobyte_asn1.BOOLEAN) || len(bytes) != 1 {
return false
}
switch bytes[0] {
case 0:
*out = false
case 1, 0xff:
*out = true
default:
return false
}
return true
}
func readTPMPolicySequence(input *cryptobyte.String) ([]TPMPolicy, error) {
var policies []TPMPolicy
for !input.Empty() {
var p TPMPolicy
var seq cryptobyte.String
if !input.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("malformed TSS2 policy")
}
tag, ok := readOptionalTag(&seq, 0)
if !ok || !tag.ReadASN1Integer(&p.CommandCode) {
return nil, errors.New("malformed TSS2 policy commandCode")
}
tag, ok = readOptionalTag(&seq, 1)
if !ok {
return nil, errors.New("malformed TSS2 policy commandPolicy")
}
if p.CommandPolicy, ok = readOctetString(&tag); !ok {
return nil, errors.New("malformed TSS2 policy commandPolicy")
}
policies = append(policies, p)
}
return policies, nil
}
func readTPMAuthPolicy(input *cryptobyte.String) ([]TPMAuthPolicy, error) {
var (
err error
authPolicy cryptobyte.String
authPolicies []TPMAuthPolicy
)
if !input.ReadASN1(&authPolicy, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("malformed TSS2 authPolicy")
}
for !authPolicy.Empty() {
var ap TPMAuthPolicy
var seq cryptobyte.String
if !authPolicy.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("malformed TSS2 authPolicy")
}
var name cryptobyte.String
if tag, ok := readOptionalTag(&seq, 0); ok {
if !tag.ReadASN1(&name, cryptobyte_asn1.UTF8String) {
return nil, errors.New("malformed TSS2 authPolicy name")
}
ap.Name = string(name)
}
var policySeq cryptobyte.String
if tag, ok := readOptionalTag(&seq, 1); ok {
if !tag.ReadASN1(&policySeq, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("malformed TSS2 authPolicy policy")
}
if ap.Policy, err = readTPMPolicySequence(&policySeq); err != nil {
return nil, errors.New("malformed TSS2 authPolicy policy")
}
}
authPolicies = append(authPolicies, ap)
}
return authPolicies, nil
}
|