Пример #1
0
func sendError(err error, ms *util.MessageStream) {
	var errStr = ""
	if err != nil {
		errStr = err.Error()
	}
	resp := &domain_service.DomainServiceResponse{ErrorMessage: &errStr}
	if _, err := ms.WriteMessage(resp); err != nil {
		log.Printf("domain_server: Error sending resp on the channel: %s\n ", err)
	}
}
Пример #2
0
func (conn *Conn) sendCredentials(ms util.MessageStream) {
	if conn.Authenticate && conn.delegation != nil {
		ms.WriteString("delegation")
		ms.WriteMessage(conn.delegation)
	} else if conn.Authenticate {
		ms.WriteString("key")
	} else {
		ms.WriteString("anonymous")
	}
}
Пример #3
0
// SetCounter sets the remote counter for this program.
func SetCounter(ms *util.MessageStream, counter uint64) error {
	rm := &RollbackMessage{
		Type: RollbackMessageType_SET_COUNTER.Enum(),
		Data: EncodeCounter(counter),
	}
	if _, err := ms.WriteMessage(rm); err != nil {
		return err
	}

	// TODO(tmroeder): we currently ignore the value of the counter returned
	// by the server.
	return checkResponse(ms)
}
Пример #4
0
// sendResult sends an OperationResult with the given value on the given stream.
func sendResult(ms util.MessageStream, result bool) error {
	res := &OperationResult{Result: proto.Bool(result)}
	ar := &Message{
		Type: MessageType_OP_RES.Enum(),
	}
	var err error
	if ar.Data, err = proto.Marshal(res); err != nil {
		return err
	}

	if _, err := ms.WriteMessage(ar); err != nil {
		return err
	}

	return nil
}
Пример #5
0
// SetHash sets the value of a hash for a given item for this program.
func SetHash(ms *util.MessageStream, item string, hash []byte) error {
	rh := &RollbackHash{
		Item: proto.String(item),
		Hash: hash,
	}
	rhb, err := proto.Marshal(rh)
	if err != nil {
		return err
	}
	rm := &RollbackMessage{
		Type: RollbackMessageType_SET_HASH.Enum(),
		Data: rhb,
	}
	if _, err := ms.WriteMessage(rm); err != nil {
		return err
	}

	return checkResponse(ms)
}
Пример #6
0
// AuthenticatePrincipal is a client method used to send a request to a
// ResourceMaster to authenticate a principal with a given certificate and a
// given set of keys.
func AuthenticatePrincipal(ms util.MessageStream, key *tao.Keys, derCert []byte) error {
	// Send the authentication request, which supposes that a server is
	// waiting to receive this request.
	c := &Message{
		Type: MessageType_AUTH_CERT.Enum(),
		Data: derCert,
	}
	if _, err := ms.WriteMessage(c); err != nil {
		return err
	}

	// Receive a challenge nonce from the server.
	var nc Message
	if err := ms.ReadMessage(&nc); err != nil {
		return err
	}
	if *nc.Type != MessageType_NONCE_CHALL {
		return fmt.Errorf("didn't receive NONCE_CHALL from the server")
	}

	// Sign the nonce.
	sn := &Message{
		Type: MessageType_SIGNED_NONCE.Enum(),
	}
	var err error
	if sn.Data, err = key.SigningKey.Sign(nc.Data, ChallengeContext); err != nil {
		return err
	}
	if _, err := ms.WriteMessage(sn); err != nil {
		return err
	}

	// Get the result from the server after verificaton.
	res, err := readResult(ms)
	if err != nil {
		return err
	}

	if !res {
		return fmt.Errorf("the signed nonce failed verification")
	}
	return nil
}
Пример #7
0
// GetCounter implements RollbackMessageType_GET_COUNTER and returns the current
// value of a counter to the requestor.
func (r *RollbackMaster) GetCounter(ms *util.MessageStream, name string) error {
	var emptyData []byte
	rr := &RollbackResponse{
		Type: RollbackMessageType_ERROR.Enum(),
		Data: emptyData,
	}

	p := r.FindRollbackProgram(name)
	if p == nil {
		if _, err := ms.WriteMessage(rr); err != nil {
			return err
		}
		return fmt.Errorf("couldn't find a rollback program with name %s", name)
	}

	rr.Type = RollbackMessageType_GET_COUNTER.Enum()
	rr.Data = EncodeCounter(p.MonotonicCounter)
	_, err := ms.WriteMessage(rr)
	return err
}
Пример #8
0
// GetHashedVerifier gets the hash of the counter and the item hash for a given
// item.
func GetHashedVerifier(ms *util.MessageStream, item string) ([]byte, error) {
	rm := &RollbackMessage{
		Type: RollbackMessageType_GET_HASHED_VERIFIER.Enum(),
		Data: []byte(item),
	}
	if _, err := ms.WriteMessage(rm); err != nil {
		return nil, err
	}

	// We can't use checkResponse here since we need to get the value out of
	// the response to read the hash.
	var rr RollbackResponse
	if err := ms.ReadMessage(&rr); err != nil {
		return nil, err
	}
	if *rr.Type == RollbackMessageType_ERROR {
		return nil, fmt.Errorf("couldn't set the counter on the remote server")
	}

	return rr.Data, nil
}
Пример #9
0
// sendOperation is a helper method that sets up the data structures needed for
// a FileOperation message like CREATE, WRITE, or READ, and sends this message
// on the MessageStream.
func sendOperation(ms util.MessageStream, mt MessageType, cert []byte, name string) error {
	fop := &FileOperation{
		Subject: cert,
		Name:    proto.String(name),
	}

	fopb, err := proto.Marshal(fop)
	if err != nil {
		return err
	}
	m := &Message{
		Type: mt.Enum(),
		Data: fopb,
	}

	if _, err := ms.WriteMessage(m); err != nil {
		return err
	}

	return nil
}
Пример #10
0
// SetCounter sets the monotonic counter for a given program to a higher value.
// It returns an error if the program doesn't exist or if the new value of the
// counter is less than the current value of the counter.
func (r *RollbackMaster) SetCounter(ms *util.MessageStream, name string, counter uint64) error {
	var emptyData []byte
	rr := &RollbackResponse{
		Type: RollbackMessageType_ERROR.Enum(),
		Data: emptyData,
	}

	p := r.FindRollbackProgram(name)
	if p == nil {
		if _, err := ms.WriteMessage(rr); err != nil {
			return err
		}
		return fmt.Errorf("couldn't find a rollback program with name %s", name)
	}

	if p.MonotonicCounter > counter {
		if _, err := ms.WriteMessage(rr); err != nil {
			return err
		}
		return fmt.Errorf("couldn't write a smaller counter value %d for %s", counter, name)
	}
	// TODO(tmroeder): this needs synchronization for any real application.
	p.MonotonicCounter = counter
	rr.Type = RollbackMessageType_SET_COUNTER.Enum()
	rr.Data = EncodeCounter(p.MonotonicCounter)
	if _, err := ms.WriteMessage(rr); err != nil {
		return err
	}

	return nil
}
Пример #11
0
// GetCounter gets the current value of the monotonic counter for a given
// program name.
func GetCounter(ms *util.MessageStream) (uint64, error) {
	// The name of the program is managed by the rollback server, not the
	// client, so it doesn't need to be passed in the message.
	rm := &RollbackMessage{
		Type: RollbackMessageType_GET_COUNTER.Enum(),
		Data: make([]byte, 0),
	}
	if _, err := ms.WriteMessage(rm); err != nil {
		return 0, err
	}

	// We can't use checkResponse here since we need to get the value out of
	// the response to read the counter.
	var rr RollbackResponse
	if err := ms.ReadMessage(&rr); err != nil {
		return 0, err
	}
	if *rr.Type == RollbackMessageType_ERROR {
		return 0, fmt.Errorf("couldn't set the counter on the remote server")
	}

	return decodeCounter(rr.Data)
}
Пример #12
0
// SetHash implements RollbackMessageType_SET_HASH by setting the value of the
// hash for a given item to a given hash value.
func (r *RollbackMaster) SetHash(ms *util.MessageStream, name string, item string, h []byte) error {
	var emptyData []byte
	rr := &RollbackResponse{
		Type: RollbackMessageType_ERROR.Enum(),
		Data: emptyData,
	}

	p := r.FindRollbackProgram(name)
	if p == nil {
		if _, err := ms.WriteMessage(rr); err != nil {
			return err
		}
		return fmt.Errorf("couldn't find a rollback program with name %s", name)
	}

	// Set the hash.
	if err := p.AddRollbackHashEntry(item, h); err != nil {
		if _, e := ms.WriteMessage(rr); e != nil {
			return e
		}
		return err
	}

	rh := &RollbackHash{
		Item: proto.String(item),
		Hash: h,
	}
	rhb, err := proto.Marshal(rh)
	if err != nil {
		if _, e := ms.WriteMessage(rr); e != nil {
			return e
		}
		return err
	}

	// TODO(tmroeder): Do you need to update the counter when you update the
	// hash?
	rr.Type = RollbackMessageType_SET_HASH.Enum()
	rr.Data = rhb
	_, err = ms.WriteMessage(rr)
	return err
}
Пример #13
0
// GetHashedVerifier gets a version of the hash for a given item along with the
// current monotonic counter.
func (r *RollbackMaster) GetHashedVerifier(ms *util.MessageStream, name string, item string) error {
	var emptyData []byte
	rr := &RollbackResponse{
		Type: RollbackMessageType_ERROR.Enum(),
		Data: emptyData,
	}

	p := r.FindRollbackProgram(name)
	if p == nil {
		if _, err := ms.WriteMessage(rr); err != nil {
			return err
		}
		return fmt.Errorf("couldn't find a rollback program with name %s", name)
	}

	h := p.FindRollbackHashEntry(item)
	if h == nil {
		if _, err := ms.WriteMessage(rr); err != nil {
			return err
		}
		return fmt.Errorf("couldn't find an item with name '%s' in program '%s'", item, name)
	}
	// Return SHA-256(Counter || Hash || Counter).
	// TODO(tmroeder): what is the justification for this protocol?
	sha256Hash := sha256.New()
	b := EncodeCounter(p.MonotonicCounter)
	sha256Hash.Write(b)
	sha256Hash.Write(h)
	sha256Hash.Write(b)
	hash := sha256Hash.Sum(nil)

	rr.Type = RollbackMessageType_GET_HASHED_VERIFIER.Enum()
	rr.Data = hash[:]
	_, err := ms.WriteMessage(rr)
	return err
}
Пример #14
0
// AuthenticatePrincipal runs a synchronous protocol to authenticate a single
// principal on a single channel. In this toy implementation, it is assumed that
// there are no other principals on the channel and that there are no other
// simultaneous channels.
func (m *ResourceMaster) AuthenticatePrincipal(ms util.MessageStream, msg *Message, programPolicy *ProgramPolicy) ([]byte, error) {
	// The certificate message is passed in by the caller as the first
	// message.

	// Process the certificate. For AUTH_CERT, the data is just the
	// certificate.
	cert, err := x509.ParseCertificate([]byte(msg.Data))
	if err != nil {
		log.Printf("couldn't Parse Certificate in AuthenticatePrincipal\n")
		return nil, err
	}

	// Set up a nonce challenge for the reply. For NONCE_CHALL, the data is
	// also just the message itself.
	reply := &Message{
		Type: MessageType_NONCE_CHALL.Enum(),
		Data: make([]byte, NonceSize),
	}
	if _, err = rand.Read(reply.Data); err != nil {
		return nil, err
	}

	// Step 1: Send a nonce to the principal.
	if _, err := ms.WriteMessage(reply); err != nil {
		return nil, err
	}

	// Step 2: Wait for the signed response.
	var s Message
	if err := ms.ReadMessage(&s); err != nil {
		return nil, err
	}
	if *s.Type != MessageType_SIGNED_NONCE {
		return nil, fmt.Errorf("received message was not SIGNED_NONCE")
	}

	// Verify the certificate against the root.
	// TODO(tmroeder): move the VerifyOptions up into the ResourceMaster.
	var opts x509.VerifyOptions
	roots := x509.NewCertPool()
	policyCert, err := x509.ParseCertificate(programPolicy.PolicyCert)
	if err != nil || policyCert == nil {
		return nil, err
	}
	roots.AddCert(policyCert)
	opts.Roots = roots
	chains, err := cert.Verify(opts)
	if chains == nil || err != nil {
		return nil, err
	}
	v, err := tao.FromX509(cert)
	if err != nil {
		return nil, err
	}
	ok, err := v.Verify(reply.Data, ChallengeContext, s.Data)
	if err != nil {
		return nil, err
	}

	if err := sendResult(ms, ok); err != nil {
		return nil, fmt.Errorf("failed to return a result to the client")
	}

	if !ok {
		return nil, fmt.Errorf("the nonce signature did not pass verification")
	}

	return msg.Data, nil
}
Пример #15
0
func sendResponse(ms util.MessageStream, resp *taoca.Response) {
	_, err := ms.WriteMessage(resp)
	if err != nil {
		fmt.Printf("error writing response: %s\n", err)
	}
}
Пример #16
0
// SendFile reads a file from disk and streams it to a receiver across a
// MessageStream. If there are sufficient bytes in the keys (at least
// hmacKeySize+aesKeySize), then it will attempt to check the integrity of the
// file with HMAC-SHA256 and decrypt it with AES-CTR-128.
func SendFile(ms util.MessageStream, dir string, filename string, keys []byte) error {
	fullpath := path.Join(dir, filename)
	fileInfo, err := os.Stat(fullpath)
	if err != nil {
		return fmt.Errorf("in SendFile: no file '%s' found: %s", fullpath, err)
	}
	file, err := os.Open(fullpath)
	if err != nil {
		return fmt.Errorf("in SendFile: can't open file '%s': %s", fullpath, err)
	}
	defer file.Close()

	// This encryption scheme uses AES-CTR with HMAC-SHA256 for integrity
	// protection.
	var hm hash.Hash
	var ctr cipher.Stream
	iv := make([]byte, ivSize)
	hasKeys := len(keys) >= minKeySize

	// The variable "left" gives the total number of bytes left to read from
	// the (maybe encrypted) file.
	left := fileInfo.Size()
	buf := make([]byte, bufferSize)
	if hasKeys {
		dec, err := aes.NewCipher(keys[:aesKeySize])
		if err != nil || dec == nil {
			return fmt.Errorf("can't create AES cipher in SendFile: %s", err)
		}
		if _, err := file.Read(iv); err != nil {
			return err
		}
		// Remove the IV from the number of remaining bytes to decrypt.
		left = left - ivSize

		// Take all the remaining key bytes for the HMAC key.
		hm = hmac.New(sha256.New, keys[aesKeySize:])
		hmacSize := hm.Size()

		// The HMAC input starts with the IV.
		hm.Write(iv)

		ctr = cipher.NewCTR(dec, iv)
		if ctr == nil {
			return fmt.Errorf("can't create AES-CTR encryption")
		}

		// Remove the HMAC-SHA256 output from the bytes to check.
		left = left - int64(hmacSize)

		// Secure decryption in this case requires reading the file
		// twice: once to check the MAC, and once to decrypt the bytes.
		// The MAC must be checked before *any* decryption occurs and
		// before *any* decrypted bytes are sent to the receiver.
		for {
			// Figure out how many bytes to read on this iteration.
			readSize := int64(bufferSize)
			final := false
			if left <= bufferSize {
				readSize = left
				final = true
			}

			// Read the (maybe encrypted) bytes from the file.
			n, err := file.Read(buf[:readSize])
			if err != nil {
				return err
			}
			left = left - int64(n)
			hm.Write(buf[:n])
			if final {
				break
			}
		}
		computed := hm.Sum(nil)
		original := buf[:hmacSize]

		// Read the file's version of the HMAC and check it securely
		// against the computed version.
		if _, err := file.Read(original); err != nil {
			return err
		}
		if !hmac.Equal(computed, original) {
			return fmt.Errorf("invalid file HMAC on decryption for file '%s'", fullpath)
		}

		// Go back to the beginning of the file (minus the IV) for
		// decryption.
		if _, err := file.Seek(ivSize, 0); err != nil {
			return fmt.Errorf("couldn't seek back to the beginning of file '%s': %s", fullpath, err)
		}

		// Reset the number of bytes so it only includes the encrypted
		// bytes.
		left = fileInfo.Size() - int64(ivSize+hmacSize)
	}

	// The input buffer, and a temporary buffer for holding decrypted
	// plaintext.
	temp := make([]byte, bufferSize)

	// Set up a framing message to use to send the data.
	m := &Message{
		Type: MessageType_FILE_NEXT.Enum(),
	}

	// Now that the integrity of the data has been verified, if needed, send
	// the data (after decryption, if necessary) to the receiver.
	for {
		// Figure out how many bytes to read on this iteration.
		readSize := int64(bufferSize)
		final := false
		if left <= bufferSize {
			readSize = left
			final = true
			m.Type = MessageType_FILE_LAST.Enum()
		}

		// Read the (maybe encrypted) bytes from the file.
		n, err := file.Read(buf[:readSize])
		if err != nil {
			return err
		}
		left = left - int64(n)

		if hasKeys {
			ctr.XORKeyStream(temp[:n], buf[:n])
			m.Data = temp[:n]
		} else {
			m.Data = buf[:n]
		}

		// Send the decrypted data to the receiver.
		if _, err := ms.WriteMessage(m); err != nil {
			return err
		}
		if final {
			break
		}
	}
	return nil
}