Beispiel #1
0
// Establishes the Tao Channel for a client using the Program Key.
// This program does all the standard client side channel negotiation.
// After negotiation is complete.  ms is the bi-directional confidentiality and
// integrity protected channel.  OpenTaoChannel returns the stream (ms) for subsequent reads
// and writes as well as the server's Tao Principal Name.
func OpenTaoChannel(programObject *TaoProgramData, serverAddr *string) (
	*util.MessageStream, *string, error) {

	// Parse policy cert and make it the root of our
	// hierarchy for verifying Tao Channel peer.
	policyCert, err := x509.ParseCertificate(programObject.PolicyCert)
	if err != nil {
		return nil, nil, errors.New("OpenTaoChannel: Can't ParseCertificate")
	}
	pool := x509.NewCertPool()
	pool.AddCert(policyCert)

	// Open the Tao Channel using the Program key.
	tlsc, err := tao.EncodeTLSCert(&programObject.ProgramKey)
	if err != nil {
		log.Fatalln("OpenTaoChannel, encode error: ", err)
	}
	// TODO(manferdelli): Replace this with tao.Dial
	conn, err := tls.Dial("tcp", *serverAddr, &tls.Config{
		RootCAs:            pool,
		Certificates:       []tls.Certificate{*tlsc},
		InsecureSkipVerify: false,
	})
	if err != nil {
		fmt.Printf("OpenTaoChannel: Can't establish channel ", err, "\n")
		return nil, nil, errors.New("OpenTaoChannel: Can't establish channel")
	}

	peerName := policyCert.Subject.OrganizationalUnit[0]

	// Stream for Tao Channel.
	ms := util.NewMessageStream(conn)
	return ms, &peerName, nil
}
Beispiel #2
0
// This function sends a DomainServiceRequest of the type GET_CRL to the domain service,
// and deserializes the response into a pkix.CertificateList containing the revoked certificates.
func RequestCrl(network, addr string) (*pkix.CertificateList, error) {
	reqType := DomainServiceRequest_GET_CRL
	request := &DomainServiceRequest{
		Type: &reqType}

	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	ms := util.NewMessageStream(conn)
	_, err = ms.WriteMessage(request)
	if err != nil {
		return nil, err
	}
	log.Printf("Sent crl request to Domain Service using network %s at address %s.",
		network, addr)
	var response DomainServiceResponse
	err = ms.ReadMessage(&response)
	if err != nil {
		return nil, err
	}
	log.Println("Got response from Domain Service.")
	if errStr := response.GetErrorMessage(); errStr != "" {
		return nil, errors.New(errStr)
	}
	parsedCrl, err := x509.ParseCRL(response.GetCrl())
	return parsedCrl, err
}
func HandleQuoteDomainRequest(conn net.Conn, policyKey *ecdsa.PrivateKey, derPolicyCert []byte) (bool, error) {
	log.Printf("HandleQuoteDomainRequest\n")

	// Expect a request with attestation from client.
	ms := util.NewMessageStream(conn)
	var request AttestCertRequest
	err := ms.ReadMessage(&request)
	if err != nil {
		log.Printf("HandleQuoteDomainRequest: Couldn't read attest request from channel")
		return false, err
	}

	resp, err := ProcessQuoteDomainRequest(request, policyKey, derPolicyCert)
	if err != nil {
		return false, err
	}

	_, err = ms.WriteMessage(resp)
	if err != nil {
		log.Printf("HandleQuoteDomainRequest: Couldn't return the attestation on the channel")
		log.Printf("\n")
		return false, err
	}
	return false, nil
}
Beispiel #4
0
// This function packages a certificate revoke request into a DomainServiceRequest of type
// REVOKE_CERTIFICATE and sends it to the domain service. It expects att to be an attestation
// signed by the domain policy key with a statement of the form:
// policyKey says revoke certificateSerialNumber
func RequestRevokeCertificate(att *tao.Attestation, network, addr string) error {
	serAtt, err := proto.Marshal(att)
	if err != nil {
		return err
	}
	reqType := DomainServiceRequest_REVOKE_CERTIFICATE
	request := &DomainServiceRequest{
		Type: &reqType,
		SerializedPolicyAttestation: serAtt}

	conn, err := net.Dial(network, addr)
	if err != nil {
		return err
	}
	ms := util.NewMessageStream(conn)
	_, err = ms.WriteMessage(request)
	if err != nil {
		return err
	}
	log.Printf("Sent cert revoke request to Domain Service using network %s at address %s.",
		network, addr)

	var response DomainServiceResponse
	err = ms.ReadMessage(&response)
	if err != nil {
		return err
	}
	log.Println("Got response from Domain Service.")
	if errStr := response.GetErrorMessage(); errStr != "" {
		return errors.New(errStr)
	}
	return nil
}
Beispiel #5
0
// NewClientCodec returns a new rpc.ClientCodec using protobuf messages on conn.
func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
	m, ok := conn.(*util.MessageStream)
	if !ok {
		// The given conn lacks framing, so add some.
		m = util.NewMessageStream(conn)
	}
	return &clientCodec{m, sync.Mutex{}}
}
Beispiel #6
0
func serve(addr, fp string, cert []byte, signingKey *tao.Keys, policy *fileproxy.ProgramPolicy) error {
	m := fileproxy.NewResourceMaster(fp)

	policyCert, err := x509.ParseCertificate(cert)
	if err != nil {
		return err
	}
	conf, err := signingKey.TLSServerConfig(policyCert)
	if err != nil {
		return err
	}
	log.Println("fileserver listening")
	sock, err := tls.Listen("tcp", addr, conf)
	if err != nil {
		return err
	}

	for {
		// Accept and handle client connections one at a time.
		conn, err := sock.Accept()
		if err != nil {
			return err
		}

		var clientName string
		if err = conn.(*tls.Conn).Handshake(); err != nil {
			log.Printf("fileserver: couldn't perform handshake: %s\n", err)
			continue
		}

		peerCerts := conn.(*tls.Conn).ConnectionState().PeerCertificates
		if peerCerts == nil {
			log.Println("fileserver: couldn't get peer list")
			continue
		}

		peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0]
		if peerCert.Raw == nil {
			log.Println("fileserver: couldn't get peer name")
			continue
		}

		if peerCert.Subject.OrganizationalUnit != nil {
			clientName = peerCert.Subject.OrganizationalUnit[0]
		}
		log.Printf("fileserver: peer name: '%s'\n", clientName)
		ms := util.NewMessageStream(conn)

		// TODO(tmroeder): support multiple simultaneous clients. This
		// requires, e.g., adding locking to the ResourceMaster.
		if err := m.RunMessageLoop(ms, policy); err != nil {
			log.Printf("fileserver: failed to run message loop: %s\n", err)
			continue
		}

		log.Println("Finished handling the client messages")
	}
}
func serve(serverAddr string, prin string, policyCert []byte, signingKey *tao.Keys, policy *fileproxy.ProgramPolicy, m *fileproxy.RollbackMaster) error {
	pc, err := x509.ParseCertificate(policyCert)
	if err != nil {
		return err
	}
	conf, err := signingKey.TLSServerConfig(pc)
	if err != nil {
		return err
	}
	log.Println("Rollback server listening")
	sock, err := tls.Listen("tcp", serverAddr, conf)
	if err != nil {
		return err
	}

	for {
		conn, err := sock.Accept()
		if err != nil {
			return err
		}
		var clientName string
		if err = conn.(*tls.Conn).Handshake(); err != nil {
			log.Println("TLS handshake failed")
			continue
		}

		peerCerts := conn.(*tls.Conn).ConnectionState().PeerCertificates
		if peerCerts == nil {
			log.Println("rollbackserver: can't get peer list")
			continue
		}

		peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0]
		if peerCert.Raw == nil {
			log.Println("rollbackserver: can't get peer name")
			continue
		}

		if peerCert.Subject.OrganizationalUnit == nil {
			log.Println("No OrganizationalUnit name in the peer certificate. Refusing the connection")
			continue
		}

		clientName = peerCert.Subject.OrganizationalUnit[0]
		ms := util.NewMessageStream(conn)
		// TODO(tmroeder): support multiple simultaneous clients.
		// Add this program as a rollback program.
		log.Printf("Adding a program with name '%s'\n", clientName)
		_ = m.AddRollbackProgram(clientName)
		if err := m.RunMessageLoop(ms, policy, clientName); err != nil {
			log.Printf("rollbackserver: failed to run message loop: %s\n", err)
		}
	}
}
Beispiel #8
0
// Dial connects to a Tao TLS server, performs a TLS handshake, and verifies
// the Attestation value of the server, checking that the server is authorized
// to execute. If keys are provided (keys!=nil), then it sends an attestation
// of its identity to the peer.
func Dial(network, addr string, guard Guard, v *Verifier, keys *Keys) (net.Conn, error) {
	tlsConfig := &tls.Config{
		RootCAs:            x509.NewCertPool(),
		InsecureSkipVerify: true,
	}

	// Set up certificate for two-way authentication.
	if keys != nil {
		if keys.Cert == nil {
			return nil, fmt.Errorf("client: can't dial with an empty client certificate\n")
		}
		tlsCert, err := EncodeTLSCert(keys)
		if err != nil {
			return nil, err
		}
		tlsConfig.Certificates = []tls.Certificate{*tlsCert}
	}

	conn, err := tls.Dial(network, addr, tlsConfig)
	if err != nil {
		return nil, err
	}

	ms := util.NewMessageStream(conn)

	// Two-way Tao handshake: send client delegation.
	if keys != nil {
		if _, err = ms.WriteMessage(keys.Delegation); err != nil {
			conn.Close()
			return nil, err
		}
	}

	// Tao handshake: read server delegation.
	var a Attestation
	if err := ms.ReadMessage(&a); err != nil {
		conn.Close()
		return nil, err
	}

	if err := AddEndorsements(guard, &a, v); err != nil {
		conn.Close()
		return nil, err
	}

	// Validate the peer certificate according to the guard.
	peerCert := conn.ConnectionState().PeerCertificates[0]
	if err := ValidatePeerAttestation(&a, peerCert, guard); err != nil {
		conn.Close()
		return nil, err
	}

	return conn, nil
}
Beispiel #9
0
// RequestDomainServiceCert requests the signed Program
// Certificate from simpledomainservice.
//  TODO: This needs to change in a way that is tao supplier dependent.
//     For tpm2 we need the ekCert and the tao and we need the data
//     for ActivateCredential.
//     For tpm1.2, we need the aikCert.
func RequestDomainServiceCert(network, addr string, requesting_key *tao.Keys,
	v *tao.Verifier) (*domain_policy.DomainCertResponse, error) {

	// Note requesting program key contains a self-signed cert to open channel.
	if requesting_key.Cert == nil {
		return nil, errors.New("RequestDomainServiceCert: Can't dial with an empty client certificate")
	}
	tlsCert, err := tao.EncodeTLSCert(requesting_key)
	if err != nil {
		return nil, err
	}
	conn, err := tls.Dial(network, addr, &tls.Config{
		RootCAs:            x509.NewCertPool(),
		Certificates:       []tls.Certificate{*tlsCert},
		InsecureSkipVerify: true,
	})
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	var request domain_policy.DomainCertRequest
	request.Attestation, err = proto.Marshal(requesting_key.Delegation)
	signer := requesting_key.SigningKey.GetSigner()
	if signer == nil {
		return nil, err
	}
	key_type := "ECDSA"
	request.KeyType = &key_type
	request.SubjectPublicKey, err = domain_policy.GetPublicDerFromEcdsaKey(&signer.PublicKey)
	if err != nil {
		return nil, err
	}

	// Tao handshake: send client delegation.
	ms := util.NewMessageStream(conn)
	_, err = ms.WriteMessage(&request)
	if err != nil {
		return nil, err
	}

	// Read the new cert
	var response domain_policy.DomainCertResponse
	err = ms.ReadMessage(&response)
	if err != nil {
		return nil, err
	}
	return &response, nil
}
Beispiel #10
0
// Handshake performs a Tao (and TLS) handshake. This occurs only once, before
// the first read or write. Users don't usually need to call this directly,
// since other functions call this as necessary.
func (conn *Conn) Handshake() error {
	// Tao handshake protocol:
	// 0. TLS handshake (executed automatically on first message)
	// 1. Client -> Server: "delgation", Tao delegation for X.509 certificate.
	// 2. Server: checks for a Tao-authorized program.
	// 3. Server -> Client: "delgation", Tao delegation for X.509 certificate.
	// 4. Client: checks for a Tao-authorized program.
	//
	// Alternate steps 1 and 2 if client authentication is not needed:
	// 1'. Client -> Server: "anonymous"
	// 2'. Server: checks if policy allows anonymous connections
	//
	// Alternate steps 3 and 4 if server authentication is not needed:
	// 3'. Server -> Client: "anonymous"
	// 4'. Client: checks if policy allows anonymous connections
	if !conn.handshakeComplete {
		if conn.T != nil {
			conn.T.Start()
		}
		// Use a new framing stream on the underlying tls to avoid recursing.
		ms := util.NewMessageStream(conn.Conn)
		if conn.isServer {
			conn.sendCredentials(ms)
			if conn.T != nil {
				conn.T.Sample("sent tao creds")
			}
			conn.recvCredentials(ms)
		} else {
			conn.sendCredentials(ms)
			if conn.T != nil {
				conn.T.Sample("sent tao creds")
			}
			conn.recvCredentials(ms)
		}
		conn.handshakeComplete = true
		conn.handshakeErr = ms.Err()
		if conn.handshakeErr != nil {
			conn.Close()
			conn.SetErr(conn.handshakeErr)
		}
		if conn.T != nil {
			conn.T.Sample("done tao handshake")
		}
	}
	return conn.handshakeErr
}
Beispiel #11
0
// RequestACLSet requests the policy from a TaoCA running an ACLGuard. Verify
// the signature with the public policy key `v`.
func RequestACLSet(network, addr string, v *Verifier) (*ACLSet, error) {

	// Establish connection wtih the CA.
	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	// Create a CArequest.
	req := &CARequest{
		Type: CAType_ACL_POLICY.Enum(),
	}

	// Send request.
	ms := util.NewMessageStream(conn)
	if _, err = ms.WriteMessage(req); err != nil {
		return nil, err
	}

	// Receive response.
	var resp CAResponse
	if err := ms.ReadMessage(&resp); err != nil {
		return nil, err
	}

	// Verify signature.
	ok, err := v.Verify(resp.SignedAclSet.SerializedAclset,
		ACLGuardSigningContext, resp.SignedAclSet.Signature)
	if !ok {
		return nil, errVerifyFailed
	} else if err != nil {
		return nil, err
	}

	if *resp.Type != CAType_ACL_POLICY {
		return nil, errInvalidResponse
	}

	var db ACLSet
	if err := proto.Unmarshal(resp.SignedAclSet.SerializedAclset, &db); err != nil {
		return nil, err
	}

	return &db, nil
}
Beispiel #12
0
// HandleCARequest checks a request from a program and responds with a truncated
// delegation signed by the policy key.
func HandleCARequest(conn net.Conn, s *Signer, guard Guard) {
	defer conn.Close() // TODO(cjpatton) This should be managed by calling function.

	// Get request.
	ms := util.NewMessageStream(conn)
	var req CARequest
	if err := ms.ReadMessage(&req); err != nil {
		fmt.Fprintln(os.Stderr, "Couldn't read from channel:", err)
		return
	}

	resp := respond(&req, s, guard)

	if _, err := ms.WriteMessage(resp); err != nil {
		fmt.Fprintln(os.Stderr, "Couldn't write to the channel:", err)
	}
}
// RequestDomainQuoteCert requests the Quote Cert
func RequestDomainQuoteCert(network, addr string, endorsementCert []byte, tpmDevice io.ReadWriter,
	quoteHandle Handle, endorsementHandle Handle, taoName string,
	ownerPw string) ([]byte, error) {

	requestingKey, derChannelCert, err := CreateTemporaryChannelKey()
	if err != nil || requestingKey == nil {
		return nil, err
	}
	channelCert, err := x509.ParseCertificate(derChannelCert)
	if err != nil || channelCert == nil {
		return nil, err
	}

	// Contact domain service.
	conn, err := tls.Dial(network, addr, &tls.Config{
		RootCAs: x509.NewCertPool(),
		// Certificates:       []tls.Certificate{tls.Certificate(*channelCert)},
		InsecureSkipVerify: true,
	})
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	// Build request.
	request, err := BuildAttestCertRequest(tpmDevice, quoteHandle, endorsementHandle, endorsementCert, taoName, ownerPw)
	if err != nil {
		return nil, err
	}

	// Send request
	ms := util.NewMessageStream(conn)
	_, err = ms.WriteMessage(request)
	if err != nil {
		return nil, err
	}

	// Read the new cert
	var response AttestCertResponse
	err = ms.ReadMessage(&response)
	if err != nil {
		return nil, err
	}

	return GetCertFromAttestResponse(tpmDevice, quoteHandle, endorsementHandle, ownerPw, response)
}
Beispiel #14
0
// Accept waits for a connect, accepts it using the underlying Conn and checks
// the attestations and the statement.
func (l *anonymousListener) Accept() (net.Conn, error) {
	c, err := l.gl.Accept()
	if err != nil {
		return nil, err
	}

	// One-way Tao handshake Protocol:
	// 0. TLS handshake (executed automatically on first message)
	// 1. Server -> Client: Tao delegation for X.509 certificate.
	// 2. Client: checks for a Tao-authorized program.
	ms := util.NewMessageStream(c)

	if _, err := ms.WriteMessage(l.delegation); err != nil {
		c.Close()
		return nil, err
	}

	return c, nil
}
Beispiel #15
0
func TestInvalidRequest(t *testing.T) {
	cal, err := net.Listen("tcp", "127.0.0.1:0")
	caAddr := cal.Addr()

	guard, keys, tmpDir, err := makeDatalogGuard()
	if err != nil {
		os.RemoveAll(tmpDir)
		t.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)
	ch := make(chan bool)

	// Test an invalid request.
	go runTCCA(t, cal, keys, guard, ch)

	conn, err := net.Dial("tcp", caAddr.String())
	if err != nil {
		t.Fatal("Failed to connect to TaoCA.")
	}
	defer conn.Close()

	// Bad CArequest, no value for bad_req.Attesation
	badReq := new(CARequest)
	badReq.Type = CAType_ATTESTATION.Enum()

	ms := util.NewMessageStream(conn)
	if _, err = ms.WriteMessage(badReq); err != nil {
		t.Logf("Failed to write to message stream: %s", err)
	}

	// Receive response.
	var resp CAResponse
	if err := ms.ReadMessage(&resp); err != nil {
		t.Fatalf("Failed to read from message stream: %s", err)
	}

	if *resp.Type != CAType_UNDEFINED {
		t.Fatalf("Response should have been UNDEFINED, got %s", resp.Type.String())
	}

	<-ch
}
Beispiel #16
0
// RequestAttestation connects to a CA and gets an attestation back from it.
// This might be a truncated attestation (in which case, the right next step is
// to verify the truncated attesation, as in RequestTruncatedAttestation), or it
// might be some other kind of attestation (like a KeyNegoServer attestation,
// which provides a policy-key-signed X.509 certificate for the auth name of
// this program).
func RequestAttestation(network, addr string, keys *Keys, v *Verifier) (*Attestation, error) {

	// Establish connection wtih the CA.
	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	// Create a CARequest.
	req := &CARequest{
		Type:        CAType_ATTESTATION.Enum(),
		Attestation: keys.Delegation,
	}

	// Tao handshake: send client delegation.
	ms := util.NewMessageStream(conn)
	if _, err = ms.WriteMessage(req); err != nil {
		return nil, err
	}

	// Read the truncated attestation and check it.
	var resp CAResponse
	if err := ms.ReadMessage(&resp); err != nil {
		return nil, err
	}

	ok, err := v.Verify(resp.Attestation.SerializedStatement,
		AttestationSigningContext, resp.Attestation.Signature)
	if !ok {
		return nil, errVerifyFailed
	} else if err != nil {
		return nil, err
	}

	if *resp.Type != CAType_ATTESTATION {
		return nil, errInvalidResponse
	}

	return resp.Attestation, nil
}
Beispiel #17
0
// This function packages a host attestation into a DomainServiceRequest of the type
// DOMAIN_CERT_REQUEST, sends it to the domain service and deserializes the response
// into an attestation that contains the domain program certificate.
func RequestProgramCert(hostAtt *tao.Attestation, verifier *tao.Verifier,
	network string, addr string) (*x509.Certificate, error) {
	serAtt, err := proto.Marshal(hostAtt)
	if err != nil {
		return nil, err
	}
	reqType := DomainServiceRequest_DOMAIN_CERT_REQUEST
	request := &DomainServiceRequest{
		Type: &reqType,
		SerializedHostAttestation: serAtt,
		ProgramKey:                verifier.MarshalKey(),
	}

	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	ms := util.NewMessageStream(conn)
	_, err = ms.WriteMessage(request)
	if err != nil {
		return nil, err
	}
	log.Printf("Sent Program cert request to Domain Service using network %s at address %s.",
		network, addr)
	var response DomainServiceResponse
	err = ms.ReadMessage(&response)
	if err != nil {
		return nil, err
	}
	log.Println("Got response from Domain Service.")

	if errStr := response.GetErrorMessage(); errStr != "" {
		return nil, errors.New(errStr)
	}
	cert, err := x509.ParseCertificate(response.GetDerProgramCert())
	if err != nil {
		return nil, err
	}
	return cert, nil
}
Beispiel #18
0
// Submit sends a CSR to a certificate authority server. The keys are used to
// authenticate to the server.
func (server *Server) Submit(keys *tao.Keys, csr *CSR) ([]*x509.Certificate, error) {
	addr := net.JoinHostPort(server.Host, server.Port)
	conn, err := tao.Dial("tcp", addr, nil /* guard */, nil /* verifier */, keys, nil)
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	ms := util.NewMessageStream(conn)

	req := &Request{CSR: csr}
	_, err = ms.WriteMessage(req)
	if err != nil {
		return nil, err
	}

	var resp Response
	if err := ms.ReadMessage(&resp); err != nil {
		return nil, err
	}
	if *resp.Status != ResponseStatus_TAOCA_OK {
		detail := "unknown error"
		if resp.ErrorDetail != nil {
			detail = *resp.ErrorDetail
		}
		return nil, fmt.Errorf("%s: %s", resp.Status, detail)
	}
	if len(resp.Cert) == 0 {
		return nil, fmt.Errorf("no certificates in CA response")
	}
	certs := make([]*x509.Certificate, len(resp.Cert))
	for i, c := range resp.Cert {
		cert, err := x509.ParseCertificate(c.X509Cert)
		if err != nil {
			return nil, err
		}
		certs[i] = cert
	}
	return certs, nil
}
Beispiel #19
0
// Return attest certificate
func (tt *TPM2Tao) Tpm2Certify(network, addr string, keyName string) ([]byte, error) {
	// Establish connection wtih the CA.
	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	rk, err := tt.loadRoot()
	if err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, rk)

	qh, err := tt.loadQuote()
	if err != nil {
		return nil, err
	}
	defer tpm2.FlushContext(tt.rw, qh)

	ms := util.NewMessageStream(conn)
	programCertMessage, err := Tpm2ConstructClientRequest(tt.rw,
		tt.rootCert, tt.pcrs,
		qh, "", tt.password, keyName)
	_, err = ms.WriteMessage(programCertMessage)
	if err != nil {
		return nil, err
	}

	var resp tpm2.ProgramCertResponseMessage
	err = ms.ReadMessage(&resp)
	if err != nil {
		return nil, err
	}
	attestCert, err := Tpm2ClientDecodeServerResponse(tt.rw, rk, qh,
		tt.password, resp)
	return attestCert, nil
}
Beispiel #20
0
// Accept waits for a connect, accepts it using the underlying Conn and checks
// the attestations and the statement.
func (l *listener) Accept() (net.Conn, error) {
	c, err := l.gl.Accept()
	if err != nil {
		return nil, err
	}

	// Tao handshake Protocol:
	// 0. TLS handshake (executed automatically on first message)
	// 1. Client -> Server: Tao delegation for X.509 certificate.
	// 2. Server: checks for a Tao-authorized program.
	// 3. Server -> Client: Tao delegation for X.509 certificate.
	// 4. Client: checks for a Tao-authorized program.
	ms := util.NewMessageStream(c)
	var a Attestation
	if err := ms.ReadMessage(&a); err != nil {
		c.Close()
		return nil, err
	}

	if err := AddEndorsements(l.guard, &a, l.verifier); err != nil {
		return nil, err
	}

	peerCert := c.(*tls.Conn).ConnectionState().PeerCertificates[0]
	if err := ValidatePeerAttestation(&a, peerCert, l.guard); err != nil {
		c.Close()
		return nil, err
	}

	if _, err := ms.WriteMessage(l.delegation); err != nil {
		c.Close()
		return nil, err
	}

	return c, nil
}
Beispiel #21
0
func main() {
	flag.Parse()
	var domain *tao.Domain
	var rootCerts *x509.CertPool
	var err error
	if *createDomainFlag {
		log.Println("Creating new domain...")
		domain, rootCerts, err = createDomain()
	} else {
		log.Println("Loading domain info...")
		domain, rootCerts, err = loadDomain()
	}
	if err != nil {
		log.Fatalln("domain_server: could not load domain:", err)
	}
	ln, err := net.Listen(*network, *addr)
	if err != nil {
		log.Fatalln("domain_server: could not listen at port:", err)
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Fatalln("domain_server: could not accept connection:", err)
		}
		// switch case
		ms := util.NewMessageStream(conn)
		var request domain_service.DomainServiceRequest
		if err := ms.ReadMessage(&request); err != nil {
			log.Printf("domain_server: Couldn't read request from channel: %s\n", err)
			continue
		}
		switch *request.Type {
		case domain_service.DomainServiceRequest_DOMAIN_CERT_REQUEST:
			_, kPrin, prog, err := domain_service.VerifyHostAttestation(
				request.GetSerializedHostAttestation(), domain, rootCerts)
			if err != nil {
				log.Printf("domain_server: Error verifying host att: %s\n", err)
				sendError(err, ms)
				continue
			}
			programKeyBytes := request.GetProgramKey()
			verifier, err := tao.UnmarshalKey(programKeyBytes)
			if err != nil {
				log.Printf("domain_server: Error parsing program key: %v\n", err)
				sendError(err, ms)
				continue
			}
			if !verifier.ToPrincipal().Identical(kPrin) {
				log.Printf("domain_server: Program key in request does not match key being attested to.")
				sendError(err, ms)
				continue
			}
			cert, err := domain_service.GenerateProgramCert(domain, serialNumber, prog,
				verifier, time.Now(), time.Now().AddDate(1, 0, 0))
			if err != nil {
				log.Printf("domain_server: Error generating program cert: %s\n", err)
				sendError(err, ms)
				continue
			}
			resp := &domain_service.DomainServiceResponse{
				DerProgramCert: cert.Raw}
			if _, err := ms.WriteMessage(resp); err != nil {
				log.Printf("domain_server: Error sending cert on the channel: %s\n ",
					err)
				continue
			}
		case domain_service.DomainServiceRequest_MANAGE_POLICY:
			// TODO(sidtelang)
		case domain_service.DomainServiceRequest_REVOKE_CERTIFICATE:
			revokedCertificates, err = domain_service.RevokeCertificate(
				request.GetSerializedPolicyAttestation(), revokedCertificates, domain)
			if err != nil {
				log.Printf("domain_server: Error revoking certificate: %s\n", err)
			}
			sendError(err, ms)
		case domain_service.DomainServiceRequest_GET_CRL:
			nowTime := time.Now()
			expireTime := time.Now().AddDate(1, 0, 0)
			crl, err := domain.Keys.SigningKey.CreateCRL(domain.Keys.Cert,
				revokedCertificates, nowTime, expireTime)
			resp := domain_service.DomainServiceResponse{}
			if err != nil {
				errStr := err.Error()
				resp.ErrorMessage = &errStr
			} else {
				resp.Crl = crl
			}
			if _, err := ms.WriteMessage(&resp); err != nil {
				log.Printf("domain_server: Error sending response on the channel: %s\n ", err)
			}
		}
	}
}
Beispiel #22
0
// First return is terminate flag.
func handleRequest(conn net.Conn, policyKey *tao.Keys, guard tao.Guard) error {
	// Expect an attestation from the client.
	ms := util.NewMessageStream(conn)
	var a tao.Attestation
	if err := ms.ReadMessage(&a); err != nil {
		return err
	}

	peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0]
	p, err := tao.ValidatePeerAttestation(&a, peerCert)
	if err != nil {
		return err
	}
	// TODO(kwalsh) most of this duplicates the work of tao.Conn
	if !guard.IsAuthorized(p, "Execute", nil) {
		return fmt.Errorf("peer is not authorized to execute, hence not authorized to connect either")
	}

	// Sign cert and put it in attestation statement
	// a consists of serialized statement, sig and SignerInfo
	// a is a says speaksfor, Delegate of speaksfor is cert and should be DER encoded

	// Get underlying says
	f, err := auth.UnmarshalForm(a.SerializedStatement)
	if err != nil {
		return err
	}

	var saysStatement *auth.Says
	if ptr, ok := f.(*auth.Says); ok {
		saysStatement = ptr
	} else if val, ok := f.(auth.Says); ok {
		saysStatement = &val
	}
	sf, ok := saysStatement.Message.(auth.Speaksfor)
	if ok != true {
		return fmt.Errorf("keynegoserver: says doesn't have a speaksfor message\n")
	}

	kprin, ok := sf.Delegate.(auth.Prin)
	if ok != true {
		return fmt.Errorf("keynegoserver: speaksfor Delegate is not auth.Prin\n")
	}
	subjectPrin, ok := sf.Delegator.(auth.Prin)
	if ok != true {
		return fmt.Errorf("keynegoserver: can't get subject principal\n")
	}
	subjectName := subjectPrin.String()
	details := &tao.X509Details{
		Country:            proto.String("US"),
		Organization:       proto.String("Google"),
		OrganizationalUnit: proto.String(subjectName),
		CommonName:         proto.String("localhost"),
	}
	subjectname := tao.NewX509Name(details)
	SerialNumber = SerialNumber + 1
	verifier, err := tao.FromPrincipal(kprin)
	if err != nil {
		return errors.New("can't get principal from kprin")
	}
	template := policyKey.SigningKey.X509Template(subjectname)
	template.IsCA = false
	clientCert, err := policyKey.CreateSignedX509(verifier, template, "default")
	if err != nil {
		return fmt.Errorf("keynegoserver: can't create client certificate: %s\n", err)
	}
	clientDERCert := clientCert.Raw
	err = ioutil.WriteFile("ClientCert", clientDERCert, os.ModePerm)

	nowTime := time.Now().UnixNano()
	expireTime := time.Now().AddDate(1, 0, 0).UnixNano()
	// Replace self signed cert in attest request
	newSpeaksFor := &auth.Speaksfor{
		Delegate:  auth.Bytes(clientDERCert),
		Delegator: sf.Delegator,
	}
	keyNegoSays := auth.Says{
		Speaker:    policyKey.SigningKey.ToPrincipal(),
		Time:       &nowTime,
		Expiration: &expireTime,
		Message:    newSpeaksFor,
	}

	delegator, ok := sf.Delegator.(auth.Prin)
	if !ok {
		return fmt.Errorf("keynegoserver: the delegator must be a principal")
	}
	found := false
	for _, sprin := range delegator.Ext {
		if !found && (sprin.Name == "Program") {
			found = true
		}
		if found {
			kprin.Ext = append(kprin.Ext, sprin)
		}
	}
	ra, err := tao.GenerateAttestation(policyKey.SigningKey, nil, keyNegoSays)
	if err != nil {
		return fmt.Errorf("Couldn't attest to the new says statement: %s", err)
	}

	if _, err := ms.WriteMessage(ra); err != nil {
		return fmt.Errorf("Couldn't return the attestation on the channel: %s", err)
	}

	return nil
}
// First return is terminate flag.
func DomainRequest(conn net.Conn, policyKey *tao.Keys, guard tao.Guard) (bool, error) {
	fmt.Printf("DomainRequest\n")
	log.Printf("DomainRequest\n")

	// Expect a request with attestation from client.
	ms := util.NewMessageStream(conn)
	var request domain_policy.DomainCertRequest
	err := ms.ReadMessage(&request)
	if err != nil {
		log.Printf("DomainRequest: Couldn't read attestation from channel:", err)
		log.Printf("\n")
		return false, err
	}

	var a tao.Attestation
	err = proto.Unmarshal(request.Attestation, &a)
	if request.KeyType == nil {
		log.Printf("Domain: Empty key type")
		return false, errors.New("Empty key type")
	}
	if *request.KeyType != "ECDSA" {
		log.Printf("Domain: bad key type")
		return false, errors.New("Domain: bad key type")
	}
	subjectPublicKey, err := domain_policy.GetEcdsaKeyFromDer(request.SubjectPublicKey)
	if err != nil {
		log.Printf("DomainRequest: can't get key from der")
		return false, errors.New("DomainRequest: can't get key from der")
	}

	// Get hash of the public key subject.
	serializedKey, err := domain_policy.SerializeEcdsaKeyToInternalName(subjectPublicKey.(*ecdsa.PublicKey))
	if err != nil || serializedKey == nil {
		log.Printf("DomainRequest: Can't serialize key to internal format\n")
		return false, errors.New("DomainRequest: Can't serialize key to internal format")
	}
	subjectKeyHash := domain_policy.GetKeyHash(serializedKey)

	peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0]
	err = tao.ValidatePeerAttestation(&a, peerCert, guard)
	/*
	   	if err != nil {
	   		log.Printf("Domain: RequestCouldn't validate peer attestation:", err)
	   		return false, err
	   	}
	   fmt.Printf("DomainRequest, peerCert: %x\n", peerCert)
	*/

	// Sign cert

	// Get Program name and key info from delegation.
	f, err := auth.UnmarshalForm(a.SerializedStatement)
	if err != nil {
		log.Printf("DomainRequest: Can't unmarshal a.SerializedStatement\n")
		return false, err
	}

	var saysStatement *auth.Says
	if ptr, ok := f.(*auth.Says); ok {
		saysStatement = ptr
	} else if val, ok := f.(auth.Says); ok {
		saysStatement = &val
	}
	sf, ok := saysStatement.Message.(auth.Speaksfor)
	if ok != true {
		log.Printf("DomainRequest: says doesnt have speaksfor message\n")
		return false, err
	}
	// this in the new key principal
	clientKeyPrincipal, ok := sf.Delegate.(auth.Prin)
	if ok != true {
		log.Printf("DomainRequest: speaksfor Delegate is not auth.Prin\n")
		return false, err
	}

	programPrincipal, ok := sf.Delegator.(auth.Prin)
	if ok != true {
		log.Printf("DomainRequest: Can't get subject principal\n")
		return false, errors.New("Can't get principal name from verifier")
	}
	programPrincipalName := programPrincipal.String()
	verified := IsAuthenticationValid(&programPrincipalName)
	if !verified {
		log.Printf("DomainRequest: name verification failed\n")
		return false, err
	}
	fmt.Printf("\nSimpleDomainService: key principal: %s, program principal: %s\n", clientKeyPrincipal, programPrincipalName)

	// Is the delegate the same key as was presented in the name in the request?
	namedHash := clientKeyPrincipal.KeyHash.(auth.Bytes)
	fmt.Printf("\nkeyhash: %x\n", namedHash)
	if bytes.Compare(subjectKeyHash[:], namedHash) != 0 {
		log.Printf("DomainRequest: named hash is wrong\n")
		fmt.Printf("DomainRequest: named hash is wrong, named: %x, computed: %x\n",
			namedHash, subjectKeyHash)
		return false, errors.New("DomainRequest: named hash is wrong")
	}

	// Sign program certificate.

	notBefore := time.Now()
	validFor := 365 * 24 * time.Hour
	notAfter := notBefore.Add(validFor)

	us := "US"
	issuerName := "Google"
	localhost := "localhost"
	x509SubjectName := &pkix.Name{
		Organization:       []string{programPrincipalName},
		OrganizationalUnit: []string{programPrincipalName},
		CommonName:         localhost,
		Country:            []string{us},
	}
	x509IssuerName := &pkix.Name{
		Organization:       []string{issuerName},
		OrganizationalUnit: []string{issuerName},
		CommonName:         localhost,
		Country:            []string{us},
	}

	// issuerName := tao.NewX509Name(&details)
	SerialNumber = SerialNumber + 1
	var sn big.Int
	certificateTemplate := x509.Certificate{
		SerialNumber: &sn,
		Issuer:       *x509IssuerName,
		Subject:      *x509SubjectName,
		NotBefore:    notBefore,
		NotAfter:     notAfter,
		KeyUsage: x509.KeyUsageCertSign |
			x509.KeyUsageKeyAgreement | x509.KeyUsageDigitalSignature,
	}

	clientCert, err := x509.CreateCertificate(rand.Reader, &certificateTemplate,
		policyKey.Cert, subjectPublicKey,
		policyKey.SigningKey.GetSigner())
	if err != nil {
		fmt.Printf("Can't create client certificate: ", err, "\n")
		return false, err
	}

	zero := int32(0)
	var ra domain_policy.DomainCertResponse
	ra.Error = &zero
	ra.SignedCert = clientCert

	// Add cert chain (just policy cert for now).
	ra.CertChain = append(ra.CertChain, policyKey.Cert.Raw)

	_, err = ms.WriteMessage(&ra)
	if err != nil {
		log.Printf("DomainRequest: Couldn't return the attestation on the channel: ", err)
		log.Printf("\n")
		return false, err
	}
	return false, nil
}
Beispiel #24
0
// This is the server. It implements the server Tao Channel negotiation corresponding
// to the client's taosupport.OpenTaoChannel.  It's possible we should move this into
// taosupport/taosupport.go since it should not vary very much from implementation to
// implementation.
func server(serverAddr string, serverProgramData *taosupport.TaoProgramData) {

	var sock net.Listener

	// Set up the single root certificate for channel negotiation which is the
	// policy key cert.
	pool := x509.NewCertPool()
	policyCert, err := x509.ParseCertificate(serverProgramData.PolicyCert)
	if err != nil {
		log.Printf("simpleserver, can't parse policyCert: ", err, "\n")
		return
	}
	// Make the policy cert the unique root of the verification chain.
	pool.AddCert(policyCert)
	tlsc, err := tao.EncodeTLSCert(&serverProgramData.ProgramKey)
	if err != nil {
		log.Printf("simpleserver, encode error: ", err, "\n")
		return
	}
	conf := &tls.Config{
		RootCAs:            pool,
		Certificates:       []tls.Certificate{*tlsc},
		InsecureSkipVerify: false,
		ClientAuth:         tls.RequireAnyClientCert,
	}

	// Listen for clients.
	log.Printf("simpleserver: Listening\n")
	sock, err = tls.Listen("tcp", serverAddr, conf)
	if err != nil {
		log.Printf("simpleserver, listen error: ", err, "\n")
		return
	}

	// Service client connections.
	for {
		log.Printf("server: at accept\n")
		conn, err := sock.Accept()
		if err != nil {
			fmt.Printf("simpleserver: can't accept connection: %s\n", err.Error())
			log.Printf("server: can't accept connection: %s\n", err.Error())
			continue
		}
		var clientName string
		err = conn.(*tls.Conn).Handshake()
		if err != nil {
			log.Printf("server: TLS handshake failed\n")
			continue
		}
		peerCerts := conn.(*tls.Conn).ConnectionState().PeerCertificates
		if peerCerts == nil {
			log.Printf("server: can't get peer list\n")
			continue
		}
		peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0]
		if peerCert.Raw == nil {
			log.Printf("server: can't get peer cert\n")
			continue
		}
		if peerCert.Subject.OrganizationalUnit == nil {
			log.Printf("server: can't get peer name\n")
			continue
		}
		clientName = peerCert.Subject.OrganizationalUnit[0]
		log.Printf("server, peer client name: %s\n", clientName)
		ms := util.NewMessageStream(conn)

		// At this point the handshake is complete and we fork a service thread
		// to communicate with this simpleclient.  ms is the bi-directional
		// confidentiality and integrity protected channel corresponding to the
		// channel opened by OpenTaoChannel.
		go serviceThead(ms, clientName, serverProgramData)
	}
}
Beispiel #25
0
func main() {
	caAddr := flag.String("caAddr", "localhost:8124", "The address of the CA for setting up a certificate signed by the policy key")
	hostcfg := flag.String("hostconfig", "tao.config", "path to host tao configuration")
	serverHost := flag.String("host", "localhost", "address for client/server")
	serverPort := flag.String("port", "8123", "port for client/server")
	rollbackServerHost := flag.String("rollbackhost", "localhost", "address for rollback client/server")
	rollbackServerPort := flag.String("rollbackport", "8129", "port for client/server")
	fileClientPassword := flag.String("password", "BogusPass", "A password for unlocking the user certificates")
	fileClientPath := flag.String("fileclient_files", "fileclient_files", "fileclient directory")
	fileClientFilePath := flag.String("stored_files", "fileclient_files/stored_files", "fileclient file directory")
	testFile := flag.String("test_file", "originalTestFile", "test file")
	fileClientKeyPath := flag.String("usercreds", "usercreds", "user keys and certs")
	country := flag.String("country", "US", "The country for the fileclient certificate")
	org := flag.String("organization", "Google", "The organization for the fileclient certificate")

	flag.Parse()

	serverAddr := net.JoinHostPort(*serverHost, *serverPort)
	hostDomain, err := tao.LoadDomain(*hostcfg, nil)
	if err != nil {
		log.Fatalln("fileclient: Can't load domain")
	}
	var derPolicyCert []byte
	if hostDomain.Keys.Cert["default"] != nil {
		derPolicyCert = hostDomain.Keys.Cert["default"].Raw
	}
	if derPolicyCert == nil {
		log.Fatalln("fileclient: Can't retrieve policy cert")
	}

	parentTao := tao.Parent()
	if err := hostDomain.ExtendTaoName(parentTao); err != nil {
		log.Fatalln("fileclient: can't extend the Tao with the policy key")
	}
	e := auth.PrinExt{Name: "fileclient_version_1"}
	if err = parentTao.ExtendTaoName(auth.SubPrin{e}); err != nil {
		log.Fatalln("fileclient: couldn't extend the tao name with the policy key")
	}

	taoName, err := parentTao.GetTaoName()
	if err != nil {
		log.Fatalln("fileclient: Can't get tao name")
	}

	// Create or read the keys for fileclient.
	// Set up a temporary cert for communication with keyNegoServer.
	// TODO(kwalsh) This may no longer be needed. Is there a significance to
	// this cert?
	name := tao.NewX509Name(&tao.X509Details{
		Country:      proto.String(*country),
		Organization: proto.String(*org),
		CommonName:   proto.String(taoName.String()),
	})
	fcKeys, err := tao.NewOnDiskTaoSealedKeys(tao.Signing|tao.Crypting, name, parentTao, *fileClientPath, tao.SealPolicyDefault)
	if err != nil {
		log.Fatalln("fileclient: couldn't set up the Tao-sealed keys:", err)
	}

	if err != nil {
		log.Fatalln("fileclient: couldn't create a self-signed cert for fileclient keys:", err)
	}

	// Contact keyNegoServer for the certificate.
	if err := fileproxy.EstablishCert("tcp", *caAddr, fcKeys, hostDomain.Keys.VerifyingKey); err != nil {
		log.Fatalf("fileclient: couldn't establish a cert signed by the policy key: %s", err)
	}

	// Get the policy cert and set up TLS.
	conf, err := fcKeys.TLSClientConfig(hostDomain.Keys.Cert["default"])
	if err != nil {
		log.Fatalln("fileclient, encode error: ", err)
	}
	conn, err := tls.Dial("tcp", serverAddr, conf)
	if err != nil {
		log.Fatalln("fileclient: can't establish channel: ", err)
	}
	ms := util.NewMessageStream(conn)

	// Before doing any tests, create a simple file to send to the server.
	testContents := `
This is a simple file to test
It has some new lines
And it doesn't have very much content.
	`

	if _, err := os.Stat(*fileClientFilePath); err != nil {
		if err := os.MkdirAll(*fileClientFilePath, 0700); err != nil {
			log.Fatalf("fileclient: couldn't create the file storage path %s: %s", *fileClientFilePath, err)
		}
	}

	sentFileName := *testFile
	sentFilePath := path.Join(*fileClientFilePath, sentFileName)
	if err := ioutil.WriteFile(sentFilePath, []byte(testContents), 0600); err != nil {
		log.Fatalf("fileclient: couldn't create a test file at %s: %s", sentFilePath, err)
	}

	// Authenticate user principal(s).
	if _, err := os.Stat(*fileClientKeyPath); err != nil {
		log.Fatalf("fileclient: couldn't get user credentials from %s: %s\n", *fileClientKeyPath, err)
	}

	// This method won't generate the right certificate in general for
	// signing, which is why we check first to make sure the right directory
	// already exists. But it will successfully read the signer and the
	// certificate.
	userKeys, err := tao.NewOnDiskPBEKeys(tao.Signing, []byte(*fileClientPassword), *fileClientKeyPath, nil)
	if err != nil {
		log.Fatalf("Couldn't read the keys from %s: %s\n", *fileClientKeyPath, err)
	}
	userCert := userKeys.Cert["default"].Raw

	// Authenticate a key to use for requests to the server.
	if err = fileproxy.AuthenticatePrincipal(ms, userKeys, userCert); err != nil {
		log.Fatalf("fileclient: can't authenticate principal: %s", err)
	}

	// Create a file.
	if err = fileproxy.CreateFile(ms, userCert, sentFileName); err != nil {
		log.Fatalln("fileclient: can't create file:", err)
	}

	// Send File.
	if err = fileproxy.WriteFile(ms, userCert, *fileClientFilePath, sentFileName); err != nil {
		log.Fatalf("fileclient: couldn't write the file %s to the server: %s", sentFileName, err)
	}

	// Get file.
	outputFileName := sentFileName + ".out"
	if err = fileproxy.ReadFile(ms, userCert, *fileClientFilePath, sentFileName, outputFileName); err != nil {
		log.Fatalf("fileclient: couldn't get file %s to output file %s: %s", sentFileName, outputFileName, err)
	}

	// TODO(tmroeder): compare the received file against the sent file.

	// Set up a TLS connection to the rollback server, just like the one to
	// the file server.
	rollbackServerAddr := net.JoinHostPort(*rollbackServerHost, *rollbackServerPort)
	rbconn, err := tls.Dial("tcp", rollbackServerAddr, conf)
	if err != nil {
		log.Fatalf("fileclient: can't establish rollback channel: %s", err)
	}
	newms := util.NewMessageStream(rbconn)

	// Create a fake hash value, and set this value for an item.
	hashLen := 32
	hash := make([]byte, hashLen)
	if _, err := rand.Read(hash); err != nil {
		log.Fatalf("fileclient: failed to read a random value for the hash")
	}

	progName := taoName.String()
	resName := "test_resource"
	if err := fileproxy.SetHash(newms, resName, hash); err != nil {
		log.Fatalf("Couldn't set the hash for program '%s', resource '%s', hash % x on the remote server: %s", progName, resName, hash, err)
	}

	// Set the counter to 10 and check that we get the same value back.
	if err := fileproxy.SetCounter(newms, uint64(10)); err != nil {
		log.Fatalf("fileclient: couldn't set the counter in the file client")
	}

	c, err := fileproxy.GetCounter(newms)
	if err != nil {
		log.Fatalf("fileclient: couldn't get the value of the counter from the rollback server")
	}

	// Get the hash verification value.
	newHash, err := fileproxy.GetHashedVerifier(newms, resName)
	if err != nil {
		log.Fatalf("fileclient: couldn't get the hashed verifier from the rollback server")
	}

	// Try to recompute the hashed verifier directly to see if it matches.
	sh := sha256.New()
	vi := fileproxy.EncodeCounter(c)
	sh.Write(vi)
	sh.Write(hash)
	sh.Write(vi)
	computed := sh.Sum(nil)
	if subtle.ConstantTimeCompare(newHash, computed) != 1 {
		log.Fatalf("fileclient: the hashed verifier % x returned by the server didn't match the value % x computed locally", newHash, computed)
	}

	log.Println("All fileclient tests pass")
}