github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/client.go (about) 1 // Copyright (c) 2014, Google, Inc. 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 "crypto/tls" 19 "crypto/x509" 20 "crypto/x509/pkix" 21 "encoding/pem" 22 "errors" 23 "fmt" 24 "net" 25 "time" 26 27 "github.com/golang/protobuf/proto" 28 "github.com/jlmucb/cloudproxy/go/tao/auth" 29 "github.com/jlmucb/cloudproxy/go/util" 30 ) 31 32 // TLS mode client/server 33 34 const ( 35 x509duration = 24 * time.Hour 36 x509keySize = 2048 37 ) 38 39 // EncodeTLSCert combines a signing key and a certificate in a single tls 40 // certificate suitable for a TLS config. 41 func EncodeTLSCert(keys *Keys) (*tls.Certificate, error) { 42 if keys.Cert == nil { 43 return nil, fmt.Errorf("client: can't encode a nil certificate") 44 } 45 certPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: keys.Cert.Raw}) 46 keyBytes, err := MarshalSignerDER(keys.SigningKey) 47 if err != nil { 48 return nil, err 49 } 50 keyPem := pem.EncodeToMemory(&pem.Block{Type: "ECDSA PRIVATE KEY", Bytes: keyBytes}) 51 52 tlsCert, err := tls.X509KeyPair(certPem, keyPem) 53 if err != nil { 54 return nil, fmt.Errorf("can't parse cert: %s\n", err.Error()) 55 } 56 return &tlsCert, nil 57 } 58 59 // generateX509 creates a fresh set of Tao-delegated keys and gets a certificate 60 // from these keys. 61 func generateX509() (*Keys, *tls.Certificate, error) { 62 keys, err := NewTemporaryTaoDelegatedKeys(Signing, Parent()) 63 if err != nil { 64 return nil, nil, err 65 } 66 67 // TODO(tmroeder): fix the name 68 signerAlg := SignerTypeFromSuiteName(TaoCryptoSuite) 69 if signerAlg == nil { 70 return nil, nil, errors.New("Cant get signer alg from ciphersuite") 71 } 72 pkInt := PublicKeyAlgFromSignerAlg(*signerAlg) 73 skInt := SignatureAlgFromSignerAlg(*signerAlg) 74 if pkInt < 0 || skInt < 0 { 75 return nil, nil, errors.New("Cant get x509 signer alg from signer alg") 76 } 77 78 cert, err := keys.SigningKey.CreateSelfSignedX509(pkInt, skInt, 1, &pkix.Name{ 79 Organization: []string{"Google Tao Demo"}}) 80 if err != nil { 81 return nil, nil, err 82 } 83 // TODO(kwalsh) keys should save cert on disk if keys are on disk 84 keys.Cert = cert 85 tc, err := EncodeTLSCert(keys) 86 return keys, tc, err 87 } 88 89 // ListenTLS creates a fresh certificate and listens for TLS connections using 90 // it. 91 func ListenTLS(network, addr string) (net.Listener, error) { 92 _, cert, err := generateX509() 93 if err != nil { 94 return nil, fmt.Errorf("server: can't create key and cert: %s\n", err.Error()) 95 } 96 return tls.Listen(network, addr, &tls.Config{ 97 RootCAs: x509.NewCertPool(), 98 Certificates: []tls.Certificate{*cert}, 99 InsecureSkipVerify: true, 100 ClientAuth: tls.RequireAnyClientCert, 101 }) 102 } 103 104 // DialTLS creates a new X.509 certs from fresh keys and dials a given TLS 105 // address. 106 func DialTLS(network, addr string) (net.Conn, error) { 107 keys, _, err := generateX509() 108 if err != nil { 109 return nil, fmt.Errorf("client: can't create key and cert: %s\n", err.Error()) 110 } 111 112 return DialTLSWithKeys(network, addr, keys) 113 } 114 115 // DialTLSWithKeys connects to a TLS server using an existing set of keys. 116 func DialTLSWithKeys(network, addr string, keys *Keys) (net.Conn, error) { 117 tlsCert, err := EncodeTLSCert(keys) 118 conn, err := tls.Dial(network, addr, &tls.Config{ 119 RootCAs: x509.NewCertPool(), 120 Certificates: []tls.Certificate{*tlsCert}, 121 InsecureSkipVerify: true, 122 }) 123 return conn, err 124 } 125 126 // DialWithNewX509 connects to a Tao TLS server, performs a TLS handshake, and 127 // exchanges Attestation values with the server, checking that this is a Tao 128 // server that is authorized to Execute. It uses a Tao Guard to perform this 129 // check. 130 func DialWithNewX509(network, addr string, guard Guard, v *Verifier) (net.Conn, error) { 131 keys, _, err := generateX509() 132 if err != nil { 133 return nil, fmt.Errorf("client: can't create key and cert: %s\n", err.Error()) 134 } 135 136 return Dial(network, addr, guard, v, keys) 137 } 138 139 // Dial connects to a Tao TLS server, performs a TLS handshake, and verifies 140 // the Attestation value of the server, checking that the server is authorized 141 // to execute. If keys are provided (keys!=nil), then it sends an attestation 142 // of its identity to the peer. 143 func Dial(network, addr string, guard Guard, v *Verifier, keys *Keys) (net.Conn, error) { 144 tlsConfig := &tls.Config{ 145 RootCAs: x509.NewCertPool(), 146 InsecureSkipVerify: true, 147 } 148 149 // Set up certificate for two-way authentication. 150 if keys != nil { 151 if keys.Cert == nil { 152 return nil, fmt.Errorf("client: can't dial with an empty client certificate\n") 153 } 154 tlsCert, err := EncodeTLSCert(keys) 155 if err != nil { 156 return nil, err 157 } 158 tlsConfig.Certificates = []tls.Certificate{*tlsCert} 159 } 160 161 conn, err := tls.Dial(network, addr, tlsConfig) 162 if err != nil { 163 return nil, err 164 } 165 166 ms := util.NewMessageStream(conn) 167 168 // Two-way Tao handshake: send client delegation. 169 if keys != nil { 170 if _, err = ms.WriteMessage(keys.Delegation); err != nil { 171 conn.Close() 172 return nil, err 173 } 174 } 175 176 // Tao handshake: read server delegation. 177 var a Attestation 178 if err := ms.ReadMessage(&a); err != nil { 179 conn.Close() 180 return nil, err 181 } 182 183 if err := AddEndorsements(guard, &a, v); err != nil { 184 conn.Close() 185 return nil, err 186 } 187 188 // Validate the peer certificate according to the guard. 189 peerCert := conn.ConnectionState().PeerCertificates[0] 190 if err := ValidatePeerAttestation(&a, peerCert, guard); err != nil { 191 conn.Close() 192 return nil, err 193 } 194 195 return conn, nil 196 } 197 198 // AddEndorsements reads the SerializedEndorsements in an attestation and adds 199 // the ones that are predicates signed by a guard's policy key. 200 func AddEndorsements(guard Guard, a *Attestation, v *Verifier) error { 201 // Before validating against the guard, check to see if there are any 202 // predicates endorsed by the policy key. This allows truncated principals 203 // to get the Tao CA to sign a statement of the form 204 // TrustedHash(ext.Program(...)). 205 for _, e := range a.SerializedEndorsements { 206 var ea Attestation 207 if err := proto.Unmarshal(e, &ea); err != nil { 208 return err 209 } 210 211 f, err := auth.UnmarshalForm(ea.SerializedStatement) 212 if err != nil { 213 return err 214 } 215 216 says, ok := f.(auth.Says) 217 if !ok { 218 return fmt.Errorf("a serialized endorsement must be an auth.Says") 219 } 220 221 // TODO(tmroeder): check that this endorsement hasn't expired. 222 pred, ok := says.Message.(auth.Pred) 223 if !ok { 224 return fmt.Errorf("the message in an endorsement must be a predicate") 225 } 226 227 signerPrin := auth.NewPrin(*ea.SignerType, ea.SignerKey) 228 229 if !signerPrin.Identical(says.Speaker) { 230 return fmt.Errorf("the speaker of an endorsement must be the signer: %v vs %v", signerPrin, says.Speaker) 231 } 232 if !v.ToPrincipal().Identical(signerPrin) { 233 return fmt.Errorf("the signer of an endorsement must be the guard's policy key") 234 } 235 if ok, err := v.Verify(ea.SerializedStatement, AttestationSigningContext, ea.Signature); (err != nil) || !ok { 236 return fmt.Errorf("the signature on an endorsement didn't pass verification") 237 } 238 239 return guard.AddRule(pred.String()) 240 } 241 242 return nil 243 } 244 245 // TruncateAttestation cuts off a delegation chain at its "Program" subprincipal 246 // extension and replaces its prefix with the given key principal. It also 247 // returns the PrinExt that represents exactly the program hash. 248 func TruncateAttestation(kprin auth.Prin, a *Attestation) (auth.Says, auth.PrinExt, error) { 249 // This attestation must have a top-level delegation to a key. Return an 250 // authorization for this program rooted in the policy key. I don't like 251 // this, since it seems like it's much riskier, since this doesn't say 252 // anything about the context in which the program is running. Fortunately, 253 // local policy rules: if a peer won't accept this cert, then the other 254 // program will have to fall back on the longer attestation. 255 stmt, err := auth.UnmarshalForm(a.SerializedStatement) 256 if err != nil { 257 return auth.Says{}, auth.PrinExt{}, err 258 } 259 260 says, ok := stmt.(auth.Says) 261 if !ok { 262 return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the serialized statement must be a says") 263 } 264 // Replace the message with one that uses the new principal, taking the last 265 // Program subprinicpal, and all its following elements. It should say: 266 // policyKey.Program(...)... says key(...) speaksfor 267 // policyKey.Program(...)..., signed policyKey. 268 sf, ok := says.Message.(auth.Speaksfor) 269 if !ok { 270 return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the message in the statement must be a speaksfor") 271 } 272 273 delegator, ok := sf.Delegator.(auth.Prin) 274 if !ok { 275 return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the delegator must be a principal") 276 } 277 278 var prog auth.PrinExt 279 found := false 280 for _, sprin := range delegator.Ext { 281 if !found && (sprin.Name == "Program") { 282 found = true 283 prog = sprin 284 } 285 286 if found { 287 kprin.Ext = append(kprin.Ext, sprin) 288 } 289 } 290 291 // TODO(tmroeder): make sure that the delegate is a key and is not, e.g., 292 // the policy key. 293 truncSpeaksfor := auth.Speaksfor{ 294 Delegate: sf.Delegate, 295 Delegator: kprin, 296 } 297 truncSays := auth.Says{ 298 Speaker: kprin, 299 Time: says.Time, 300 Expiration: says.Expiration, 301 Message: truncSpeaksfor, 302 } 303 304 return truncSays, prog, nil 305 } 306 307 // IdenticalDelegations checks to see if two Form values are Says and are 308 // identical delegations (i.e., the Message must be an auth.Speaksfor). This 309 // function is not in the auth package, since it's specific to a particular 310 // pattern. 311 func IdenticalDelegations(s, t auth.Form) bool { 312 ss, ok := s.(auth.Says) 313 if !ok { 314 return false 315 } 316 st, ok := t.(auth.Says) 317 if !ok { 318 return false 319 } 320 if !ss.Speaker.Identical(st.Speaker) { 321 return false 322 } 323 324 if (ss.Time == nil) != (st.Time == nil) { 325 return false 326 } 327 if (ss.Time != nil) && (*ss.Time != *st.Time) { 328 return false 329 } 330 if (ss.Expiration == nil) != (st.Expiration == nil) { 331 return false 332 } 333 if (ss.Expiration != nil) && (*ss.Expiration != *st.Expiration) { 334 return false 335 } 336 337 sfs, ok := ss.Message.(auth.Speaksfor) 338 if !ok { 339 return false 340 } 341 sft, ok := ss.Message.(auth.Speaksfor) 342 if !ok { 343 return false 344 } 345 346 if !sfs.Delegate.Identical(sft.Delegate) || !sfs.Delegator.Identical(sft.Delegator) { 347 return false 348 } 349 350 return true 351 }