github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/attestation.go (about) 1 // Copyright (c) 2014, Kevin Walsh. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tao 16 17 import ( 18 "time" 19 20 "github.com/golang/protobuf/proto" 21 "github.com/google/go-tpm/tpm" 22 "github.com/jlmucb/cloudproxy/go/tao/auth" 23 "github.com/jlmucb/cloudproxy/go/tpm2" 24 ) 25 26 // ValidSigner checks the signature on an attestation and, if so, returns the 27 // principal name for the signer. 28 func (a *Attestation) ValidSigner() (auth.Prin, error) { 29 signer := auth.NewPrin(*a.SignerType, a.SignerKey) 30 switch *a.SignerType { 31 case "tpm": 32 // The PCRs are contained in the Speaker of an auth.Says statement that 33 // makes up the a.SerializedStatement. 34 f, err := auth.UnmarshalForm(a.SerializedStatement) 35 if err != nil { 36 return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err) 37 } 38 39 // A TPM attestation must be an auth.Says. 40 says, ok := f.(auth.Says) 41 if !ok { 42 return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement") 43 } 44 45 // Signer is tpm; use tpm-specific signature verification. Extract the 46 // PCRs from the issuer name, unmarshal the key as an RSA key, and call 47 // tpm.VerifyQuote(). 48 speaker, ok := says.Speaker.(auth.Prin) 49 if !ok { 50 return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin") 51 } 52 pcrNums, pcrVals, err := extractPCRs(speaker) 53 if err != nil { 54 return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err) 55 } 56 57 pk, err := extractTPMKey(a.SignerKey) 58 if err != nil { 59 return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err) 60 } 61 if err := tpm.VerifyQuote(pk, a.SerializedStatement, a.Signature, pcrNums, pcrVals); err != nil { 62 return auth.Prin{}, newError("tao: TPM quote failed verification: %s", err) 63 } 64 65 return signer, nil 66 case "tpm2": 67 // TODO -- tpm2 68 // The PCRs are contained in the Speaker of an auth.Says statement that 69 // makes up the a.SerializedStatement. 70 f, err := auth.UnmarshalForm(a.SerializedStatement) 71 if err != nil { 72 return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err) 73 } 74 75 // put this back in 76 // A TPM attestation must be an auth.Says. 77 says, ok := f.(auth.Says) 78 if !ok { 79 return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement") 80 } 81 82 // Signer is tpm; use tpm-specific signature verification. Extract the 83 // PCRs from the issuer name, unmarshal the key as an RSA key, and call 84 // tpm2.VerifyQuote(). 85 speaker, ok := says.Speaker.(auth.Prin) 86 if !ok { 87 return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin") 88 } 89 90 key, err := extractTPM2Key(a.SignerKey) 91 if err != nil { 92 return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err) 93 } 94 pcrNums, pcrVal, err := extractTpm2PCRs(speaker) 95 if err != nil { 96 return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err) 97 } 98 // Note: Hash algorithm used below must match hash algorithm in the signing scheme 99 // used for the quote key. 100 expectedPcrDigest, err := tpm2.ComputePcrDigest(tpm2.AlgTPM_ALG_SHA1, pcrVal) 101 if err != nil { 102 return auth.Prin{}, newError("tao: Error computing PCR digest: %s", err) 103 } 104 ok, err = tpm2.VerifyTpm2Quote(a.SerializedStatement, 105 pcrNums, expectedPcrDigest, a.Tpm2QuoteStructure, a.Signature, 106 key) 107 if err != nil { 108 return auth.Prin{}, newError("tao: TPM quote verification error: %s", err) 109 } 110 if !ok { 111 return auth.Prin{}, newError("tao: TPM quote failed verification") 112 } 113 return signer, nil 114 case "key": 115 // Signer is ECDSA key, use Tao signature verification. 116 // TODO v, err := UnmarshalKey(a.SignerKey) 117 v, err := VerifierKeyFromCanonicalKeyBytes(a.SignerKey) 118 if err != nil { 119 return auth.Prin{}, err 120 } 121 ok, err := v.Verify(a.SerializedStatement, AttestationSigningContext, a.Signature) 122 if err != nil { 123 return auth.Prin{}, err 124 } 125 if !ok { 126 return auth.Prin{}, newError("tao: attestation signature invalid") 127 } 128 return signer, nil 129 default: 130 return auth.Prin{}, newError("tao: attestation signer principal unrecognized: %s", signer.String()) 131 } 132 } 133 134 // Validate checks whether an attestation is valid and, if so, it returns the 135 // statement conveyed by the attestation. 136 func (a *Attestation) Validate() (auth.Says, error) { 137 signer, err := a.ValidSigner() 138 if err != nil { 139 return auth.Says{}, err 140 } 141 f, err := auth.UnmarshalForm(a.SerializedStatement) 142 if err != nil { 143 return auth.Says{}, err 144 } 145 var stmt *auth.Says 146 if ptr, ok := f.(*auth.Says); ok { 147 stmt = ptr 148 } else if val, ok := f.(auth.Says); ok { 149 stmt = &val 150 } else { 151 return auth.Says{}, newError("tao: attestation statement has wrong type: %T", f) 152 } 153 154 if a.SerializedDelegation == nil { 155 // Case (1), no delegation present. 156 // Require that stmt.Speaker be a subprincipal of (or identical to) a.signer. 157 if !auth.SubprinOrIdentical(stmt.Speaker, signer) { 158 return auth.Says{}, newError("tao: attestation statement signer (%v) does not evidently speak for issuer (%v)", signer, stmt.Speaker) 159 } 160 } else { 161 // Case (2), delegation present. 162 // Require that: 163 // - delegation conveys delegator says delegate speaksfor delegator, 164 // - a.signer speaks for delegate 165 // - and delegator speaks for s.Speaker 166 var da Attestation 167 if err := proto.Unmarshal(a.SerializedDelegation, &da); err != nil { 168 return auth.Says{}, err 169 } 170 delegationStatement, err := da.Validate() 171 if err != nil { 172 return auth.Says{}, err 173 } 174 var delegation *auth.Speaksfor 175 if ptr, ok := delegationStatement.Message.(*auth.Speaksfor); ok { 176 delegation = ptr 177 } else if val, ok := delegationStatement.Message.(auth.Speaksfor); ok { 178 delegation = &val 179 } else { 180 return auth.Says{}, newError("tao: attestation delegation is wrong type") 181 } 182 if !delegationStatement.Speaker.Identical(delegation.Delegator) { 183 return auth.Says{}, newError("tao: attestation delegation is invalid") 184 } 185 if !auth.SubprinOrIdentical(delegation.Delegate, signer) { 186 return auth.Says{}, newError("tao: attestation delegation irrelevant to signer") 187 } 188 if !auth.SubprinOrIdentical(stmt.Speaker, delegation.Delegator) { 189 return auth.Says{}, newError("tao: attestation delegation irrelevant to issuer") 190 } 191 if stmt.Time == nil { 192 stmt.Time = delegationStatement.Time 193 } else if delegationStatement.Time != nil && *stmt.Time < *delegationStatement.Time { 194 stmt.Time = delegationStatement.Time 195 } 196 if stmt.Expiration == nil { 197 stmt.Expiration = delegationStatement.Expiration 198 } else if delegationStatement.Expiration != nil && *stmt.Expiration > *delegationStatement.Expiration { 199 stmt.Expiration = delegationStatement.Expiration 200 } 201 } 202 return *stmt, nil 203 } 204 205 // GenerateAttestation uses the signing key to generate an attestation for this 206 // statement. 207 func GenerateAttestation(s *Signer, delegation []byte, stmt auth.Says) (*Attestation, error) { 208 t := time.Now() 209 if stmt.Time == nil { 210 i := t.UnixNano() 211 stmt.Time = &i 212 } 213 214 if stmt.Expiration == nil { 215 i := t.Add(365 * 24 * time.Hour).UnixNano() 216 stmt.Expiration = &i 217 } 218 219 ser := auth.Marshal(stmt) 220 sig, err := s.Sign(ser, AttestationSigningContext) 221 if err != nil { 222 return nil, err 223 } 224 225 sk, err := s.GetVerifierFromSigner().CanonicalKeyBytesFromVerifier() 226 if err != nil { 227 return nil, err 228 } 229 a := &Attestation{ 230 SerializedStatement: ser, 231 Signature: sig, 232 SignerType: proto.String("key"), 233 SignerKey: sk, 234 } 235 236 if len(delegation) > 0 { 237 a.SerializedDelegation = delegation 238 } 239 240 return a, nil 241 }