Beispiel #1
0
// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
// hashed is the result of hashing the input message using the given hash
// function and sig is the signature. A valid signature is indicated by
// returning a nil error.
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
	hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
	if err != nil {
		return
	}

	tLen := len(prefix) + hashLen
	k := (pub.N.BitLen() + 7) / 8
	if k < tLen+11 {
		err = VerificationError{}
		return
	}

	c := new(big.Int).SetBytes(sig)
	m := encrypt(new(big.Int), pub, c)
	em := leftPad(m.Bytes(), k)
	// EM = 0x00 || 0x01 || PS || 0x00 || T

	ok := subtle.ConstantTimeByteEq(em[0], 0)
	ok &= subtle.ConstantTimeByteEq(em[1], 1)
	ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed)
	ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix)
	ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0)

	for i := 2; i < k-tLen-1; i++ {
		ok &= subtle.ConstantTimeByteEq(em[i], 0xff)
	}

	if ok != 1 {
		return VerificationError{}
	}

	return nil
}
Beispiel #2
0
/*
 Checks the username/password combination from the request. Returns
 either an empty string (authentication failed) or the name of the
 authenticated user.

 Supports MD5 and SHA1 password entries
*/
func (a *BasicAuth) CheckAuth(r *http.Request) string {
	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
	if len(s) != 2 || s[0] != "Basic" {
		return ""
	}

	b, err := base64.StdEncoding.DecodeString(s[1])
	if err != nil {
		return ""
	}
	pair := strings.SplitN(string(b), ":", 2)
	if len(pair) != 2 {
		return ""
	}
	passwd := a.Secrets(pair[0], a.Realm)
	if passwd == "" {
		return ""
	}
	if strings.HasPrefix(passwd, "{SHA}") {
		d := sha1.New()
		d.Write([]byte(pair[1]))
		if subtle.ConstantTimeCompare([]byte(passwd[5:]), []byte(base64.StdEncoding.EncodeToString(d.Sum(nil)))) != 1 {
			return ""
		}
	} else {
		e := NewMD5Entry(passwd)
		if e == nil {
			return ""
		}
		if subtle.ConstantTimeCompare([]byte(passwd), MD5Crypt([]byte(pair[1]), e.Salt, e.Magic)) != 1 {
			return ""
		}
	}
	return pair[0]
}
Beispiel #3
0
func secureCompare(given, actual string) bool {
	if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
		return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
	}
	/* Securely compare actual to itself to keep constant time, but always return false */
	return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
}
Beispiel #4
0
// CheckHashes verifies all the checksums specified by the "hashes" of the payload.
func CheckHashes(payload []byte, hashes Hashes) error {
	cnt := 0

	// k, v indicate the hash algorithm and the corresponding value
	for k, v := range hashes {
		switch k {
		case notary.SHA256:
			checksum := sha256.Sum256(payload)
			if subtle.ConstantTimeCompare(checksum[:], v) == 0 {
				return ErrMismatchedChecksum{alg: notary.SHA256}
			}
			cnt++
		case notary.SHA512:
			checksum := sha512.Sum512(payload)
			if subtle.ConstantTimeCompare(checksum[:], v) == 0 {
				return ErrMismatchedChecksum{alg: notary.SHA512}
			}
			cnt++
		}
	}

	if cnt == 0 {
		return fmt.Errorf("at least one supported hash needed")
	}

	return nil
}
Beispiel #5
0
// CheckHashes verifies all the checksums specified by the "hashes" of the payload.
func CheckHashes(payload []byte, name string, hashes Hashes) error {
	cnt := 0

	// k, v indicate the hash algorithm and the corresponding value
	for k, v := range hashes {
		switch k {
		case notary.SHA256:
			checksum := sha256.Sum256(payload)
			if subtle.ConstantTimeCompare(checksum[:], v) == 0 {
				return ErrMismatchedChecksum{alg: notary.SHA256, name: name, expected: hex.EncodeToString(v)}
			}
			cnt++
		case notary.SHA512:
			checksum := sha512.Sum512(payload)
			if subtle.ConstantTimeCompare(checksum[:], v) == 0 {
				return ErrMismatchedChecksum{alg: notary.SHA512, name: name, expected: hex.EncodeToString(v)}
			}
			cnt++
		}
	}

	if cnt == 0 {
		return ErrMissingMeta{Role: name}
	}

	return nil
}
func TestDecodeHashPayloadReturnsCorrectString(t *testing.T) {

	hashPayload := "9:1111:64:bXlzYWx0:bXlwYXNzd29yZA=="

	r, n, l, salt, p, err := decodeHashPaylaod(hashPayload)

	if err != nil {
		t.Errorf("Error encountered, %v", err)
	}

	saltRes := subtle.ConstantTimeCompare(salt, []byte("mysalt"))
	pRes := subtle.ConstantTimeCompare(p, []byte("mypassword"))

	if !(saltRes == 1) {
		t.Error("aggg f****d")
	}

	if !(pRes == 1) {
		t.Errorf("incorrect password hash decoded expected: mypassword but got %s", p)
	}

	if l != 64 {
		t.Errorf("incorrect passwordHash length decoded expected: 64 but got %d", l)
	}

	if r != 9 {
		t.Errorf("incorrect number of rounds decoded expected: 9 but got %d", r)
	}
	if n != 1111 {
		t.Errorf("incorrect cost decoded expected: 1111 but got %d", n)
	}
}
Beispiel #7
0
func NewHtpasswdValidator(filename string) Validator {
	provider := HtpasswdFileProvider(filename)

	return func(username string, passwd string) bool {
		// realm is ignored
		hashedPw := provider(username, "")

		if strings.HasPrefix(hashedPw, "{SHA}") {
			d := sha1.New()
			d.Write([]byte(passwd))

			if subtle.ConstantTimeCompare([]byte(hashedPw[5:]), []byte(base64.StdEncoding.EncodeToString(d.Sum(nil)))) != 1 {
				return false
			}
		} else {
			e := NewMD5Entry(hashedPw)
			if e == nil {
				return false
			}
			if subtle.ConstantTimeCompare([]byte(hashedPw), MD5Crypt([]byte(passwd), e.Salt, e.Magic)) != 1 {
				return false
			}
		}
		return true
	}
}
Beispiel #8
0
// validateMetadata matches the given client nonce and pending time with the
// one cached in the identity whitelist during the previous login. But, if
// reauthentication is disabled, login attempt is failed immediately.
func validateMetadata(clientNonce, pendingTime string, storedIdentity *whitelistIdentity, roleEntry *awsRoleEntry) error {
	// For sanity
	if !storedIdentity.DisallowReauthentication && storedIdentity.ClientNonce == "" {
		return fmt.Errorf("client nonce missing in stored identity")
	}

	// If reauthentication is disabled or if the nonce supplied matches a
	// predefied nonce which indicates reauthentication to be disabled,
	// authentication will not succeed.
	if storedIdentity.DisallowReauthentication ||
		subtle.ConstantTimeCompare([]byte(reauthenticationDisabledNonce), []byte(clientNonce)) == 1 {
		return fmt.Errorf("reauthentication is disabled")
	}

	givenPendingTime, err := time.Parse(time.RFC3339, pendingTime)
	if err != nil {
		return err
	}

	storedPendingTime, err := time.Parse(time.RFC3339, storedIdentity.PendingTime)
	if err != nil {
		return err
	}

	// When the presented client nonce does not match the cached entry, it
	// is either that a rogue client is trying to login or that a valid
	// client suffered a migration. The migration is detected via
	// pendingTime in the instance metadata, which sadly is only updated
	// when an instance is stopped and started but *not* when the instance
	// is rebooted. If reboot survivability is needed, either
	// instrumentation to delete the instance ID from the whitelist is
	// necessary, or the client must durably store the nonce.
	//
	// If the `allow_instance_migration` property of the registered role is
	// enabled, then the client nonce mismatch is ignored, as long as the
	// pending time in the presented instance identity document is newer
	// than the cached pending time. The new pendingTime is stored and used
	// for future checks.
	//
	// This is a weak criterion and hence the `allow_instance_migration`
	// option should be used with caution.
	if subtle.ConstantTimeCompare([]byte(clientNonce), []byte(storedIdentity.ClientNonce)) != 1 {
		if !roleEntry.AllowInstanceMigration {
			return fmt.Errorf("client nonce mismatch")
		}
		if roleEntry.AllowInstanceMigration && !givenPendingTime.After(storedPendingTime) {
			return fmt.Errorf("client nonce mismatch and instance meta-data incorrect")
		}
	}

	// Ensure that the 'pendingTime' on the given identity document is not
	// before the 'pendingTime' that was used for previous login. This
	// disallows old metadata documents from being used to perform login.
	if givenPendingTime.Before(storedPendingTime) {
		return fmt.Errorf("instance meta-data is older than the one used for previous login")
	}
	return nil
}
Beispiel #9
0
// Winnow the data.
func Winnow(authKey *[32]byte, noncePrfx, in []byte) ([]byte, error) {
	if len(in)%EnlargeFactor != 0 {
		return nil, errors.New("Invalid data size")
	}
	out := make([]byte, len(in)/EnlargeFactor)
	keys := make([]byte, 8*64)
	nonce := make([]byte, 24)
	copy(nonce[:8], noncePrfx)
	var i int
	var v byte
	tag := new([16]byte)
	macKey := new([32]byte)
	defer zero(macKey[:])
	var is01 bool
	var is00 bool
	var is11 bool
	var is10 bool
	for n := 0; n < len(out); n++ {
		binary.BigEndian.PutUint64(nonce[16:], uint64(n))
		salsa20.XORKeyStream(keys, keys, nonce, authKey)
		v = 0
		for i = 0; i < 8; i++ {
			copy(macKey[:], keys[64*i:64*i+32])
			poly1305.Sum(tag, []byte("1"), macKey)
			is01 = subtle.ConstantTimeCompare(
				tag[:],
				in[16*(n*16+i*2):16*(n*16+i*2+1)],
			) == 1
			poly1305.Sum(tag, []byte("0"), macKey)
			is00 = subtle.ConstantTimeCompare(
				tag[:],
				in[16*(n*16+i*2):16*(n*16+i*2+1)],
			) == 1
			copy(macKey[:], keys[64*i+32:64*i+64])
			poly1305.Sum(tag, []byte("1"), macKey)
			is11 = subtle.ConstantTimeCompare(
				tag[:],
				in[16*(n*16+i*2+1):16*(n*16+i*2+2)],
			) == 1
			poly1305.Sum(tag, []byte("0"), macKey)
			is10 = subtle.ConstantTimeCompare(
				tag[:],
				in[16*(n*16+i*2+1):16*(n*16+i*2+2)],
			) == 1
			if !((is01 && is10) || (is00 && is11)) {
				zero(keys)
				return nil, errors.New("Invalid authenticator received")
			}
			if is11 {
				v = v | 1<<uint8(i)
			}
		}
		out[n] = v
		zero(keys)
	}
	return out, nil
}
func (sshClient *sshClient) passwordCallback(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {

	expectedSessionIDLength := 2 * common.PSIPHON_API_CLIENT_SESSION_ID_LENGTH
	expectedSSHPasswordLength := 2 * SSH_PASSWORD_BYTE_LENGTH

	var sshPasswordPayload struct {
		SessionId   string `json:"SessionId"`
		SshPassword string `json:"SshPassword"`
	}
	err := json.Unmarshal(password, &sshPasswordPayload)
	if err != nil {

		// Backwards compatibility case: instead of a JSON payload, older clients
		// send the hex encoded session ID prepended to the SSH password.
		// Note: there's an even older case where clients don't send any session ID,
		// but that's no longer supported.
		if len(password) == expectedSessionIDLength+expectedSSHPasswordLength {
			sshPasswordPayload.SessionId = string(password[0:expectedSessionIDLength])
			sshPasswordPayload.SshPassword = string(password[expectedSSHPasswordLength:len(password)])
		} else {
			return nil, common.ContextError(fmt.Errorf("invalid password payload for %q", conn.User()))
		}
	}

	if !isHexDigits(sshClient.sshServer.support, sshPasswordPayload.SessionId) ||
		len(sshPasswordPayload.SessionId) != expectedSessionIDLength {
		return nil, common.ContextError(fmt.Errorf("invalid session ID for %q", conn.User()))
	}

	userOk := (subtle.ConstantTimeCompare(
		[]byte(conn.User()), []byte(sshClient.sshServer.support.Config.SSHUserName)) == 1)

	passwordOk := (subtle.ConstantTimeCompare(
		[]byte(sshPasswordPayload.SshPassword), []byte(sshClient.sshServer.support.Config.SSHPassword)) == 1)

	if !userOk || !passwordOk {
		return nil, common.ContextError(fmt.Errorf("invalid password for %q", conn.User()))
	}

	sessionID := sshPasswordPayload.SessionId

	sshClient.Lock()
	sshClient.sessionID = sessionID
	geoIPData := sshClient.geoIPData
	sshClient.Unlock()

	// Store the GeoIP data associated with the session ID. This makes the GeoIP data
	// available to the web server for web transport Psiphon API requests. To allow for
	// post-tunnel final status requests, the lifetime of cached GeoIP records exceeds
	// the lifetime of the sshClient, and that's why this distinct session cache exists.
	sshClient.sshServer.support.GeoIPService.SetSessionCache(sessionID, geoIPData)

	return nil, nil
}
Beispiel #11
0
func SecureCompare(given, actual []byte) bool {
	if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
		if subtle.ConstantTimeCompare(given, actual) == 1 {
			return true
		}
		return false
	}
	// Securely compare actual to itself to keep constant time, but always return false
	if subtle.ConstantTimeCompare(actual, actual) == 1 {
		return false
	}
	return false
}
func (sshClient *sshClient) passwordCallback(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {

	var sshPasswordPayload struct {
		SessionId   string `json:"SessionId"`
		SshPassword string `json:"SshPassword"`
	}
	err := json.Unmarshal(password, &sshPasswordPayload)
	if err != nil {

		// Backwards compatibility case: instead of a JSON payload, older clients
		// send the hex encoded session ID prepended to the SSH password.
		// Note: there's an even older case where clients don't send any session ID,
		// but that's no longer supported.
		if len(password) == 2*psiphon.PSIPHON_API_CLIENT_SESSION_ID_LENGTH+2*SSH_PASSWORD_BYTE_LENGTH {
			sshPasswordPayload.SessionId = string(password[0 : 2*psiphon.PSIPHON_API_CLIENT_SESSION_ID_LENGTH])
			sshPasswordPayload.SshPassword = string(password[2*psiphon.PSIPHON_API_CLIENT_SESSION_ID_LENGTH : len(password)])
		} else {
			return nil, psiphon.ContextError(fmt.Errorf("invalid password payload for %q", conn.User()))
		}
	}

	if !isHexDigits(sshClient.sshServer.support, sshPasswordPayload.SessionId) {
		return nil, psiphon.ContextError(fmt.Errorf("invalid session ID for %q", conn.User()))
	}

	userOk := (subtle.ConstantTimeCompare(
		[]byte(conn.User()), []byte(sshClient.sshServer.support.Config.SSHUserName)) == 1)

	passwordOk := (subtle.ConstantTimeCompare(
		[]byte(sshPasswordPayload.SshPassword), []byte(sshClient.sshServer.support.Config.SSHPassword)) == 1)

	if !userOk || !passwordOk {
		return nil, psiphon.ContextError(fmt.Errorf("invalid password for %q", conn.User()))
	}

	psiphonSessionID := sshPasswordPayload.SessionId

	sshClient.Lock()
	sshClient.psiphonSessionID = psiphonSessionID
	geoIPData := sshClient.geoIPData
	sshClient.Unlock()

	// Store the GeoIP data associated with the session ID. This makes the GeoIP data
	// available to the web server for web transport Psiphon API requests.
	sshClient.sshServer.support.GeoIPService.SetSessionCache(
		psiphonSessionID, geoIPData)

	return nil, nil
}
Beispiel #13
0
// Match determines whether this KeyAuthorization matches the given token and key
func (ka KeyAuthorization) Match(token string, key *jose.JsonWebKey) bool {
	if key == nil {
		return false
	}

	thumbprint, err := Thumbprint(key)
	if err != nil {
		return false
	}

	tokensEqual := subtle.ConstantTimeCompare([]byte(token), []byte(ka.Token))
	thumbprintsEqual := subtle.ConstantTimeCompare([]byte(thumbprint), []byte(ka.Thumbprint))

	return tokensEqual == 1 && thumbprintsEqual == 1
}
Beispiel #14
0
// Returns true if the provided message is unsigned or has a valid signature
// from one of the provided signers.
func authenticateMessage(signers map[string]Signer, header *Header, msg []byte) bool {
	digest := header.GetHmac()
	if digest != nil {
		var key string
		signer := fmt.Sprintf("%s_%d", header.GetHmacSigner(),
			header.GetHmacKeyVersion())
		if s, ok := signers[signer]; ok {
			key = s.HmacKey
		} else {
			return false
		}

		var hm hash.Hash
		switch header.GetHmacHashFunction() {
		case Header_MD5:
			hm = hmac.New(md5.New, []byte(key))
		case Header_SHA1:
			hm = hmac.New(sha1.New, []byte(key))
		}
		hm.Write(msg)
		expectedDigest := hm.Sum(nil)
		if subtle.ConstantTimeCompare(digest, expectedDigest) != 1 {
			return false
		}
	}
	return true
}
Beispiel #15
0
func (uh *UsersSharedsecretHandler) Validate(snr *SessionNonceRequest, request *http.Request) (string, error) {

	// Parse UseridCombo.
	useridCombo := strings.SplitN(snr.UseridCombo, ":", 3)
	if len(useridCombo) < 2 {
		return "", errors.New("invalid useridcombo")
	}
	// TODO(longsleep): Add support for third field which provides the username.
	expirationString, userid := useridCombo[0], useridCombo[1]

	expiration, err := strconv.ParseInt(expirationString, 10, 64)
	if err != nil {
		return "", err
	}

	// Check expiration.
	if time.Unix(expiration, 0).Before(time.Now()) {
		return "", errors.New("expired secret")
	}

	secret := uh.createHMAC(snr.UseridCombo)
	if subtle.ConstantTimeCompare([]byte(snr.Secret), []byte(secret)) != 1 {
		return "", errors.New("invalid secret")
	}

	return userid, nil

}
Beispiel #16
0
// EqualToPassword returns true if the password hash was derived from the provided password.
// This function uses constant time comparison.
func (ph *PasswordHash) EqualToPassword(password string) bool {
	provided := NewSaltIter(password, ph.Salt, ph.Iter)
	if len(ph.Hash) != len(provided.Hash) {
		return false
	}
	return subtle.ConstantTimeCompare(ph.Hash, provided.Hash) == 1
}
Beispiel #17
0
// Open decrypts and authenticates the ciphertext.
func (ctx *cbcAEAD) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
	if len(ciphertext) < ctx.authtagBytes {
		return nil, errors.New("square/go-jose: invalid ciphertext (too short)")
	}

	offset := len(ciphertext) - ctx.authtagBytes
	expectedTag := ctx.computeAuthTag(data, nonce, ciphertext[:offset])
	match := subtle.ConstantTimeCompare(expectedTag, ciphertext[offset:])
	if match != 1 {
		return nil, errors.New("square/go-jose: invalid ciphertext (auth tag mismatch)")
	}

	cbc := cipher.NewCBCDecrypter(ctx.blockCipher, nonce)

	// Make copy of ciphertext buffer, don't want to modify in place
	buffer := append([]byte{}, []byte(ciphertext[:offset])...)

	if len(buffer)%ctx.blockCipher.BlockSize() > 0 {
		return nil, errors.New("square/go-jose: invalid ciphertext (invalid length)")
	}

	cbc.CryptBlocks(buffer, buffer)

	// Remove padding
	plaintext, err := unpadBuffer(buffer, ctx.blockCipher.BlockSize())
	if err != nil {
		return nil, err
	}

	ret, out := resize(dst, len(dst)+len(plaintext))
	copy(out, plaintext)

	return ret, nil
}
Beispiel #18
0
// Verify returns true iff sig is a valid signature of message by publicKey.
func Verify(publicKey *[PublicKeySize]byte, message []byte, sig *[SignatureSize]byte) bool {
	if sig[63]&224 != 0 {
		return false
	}

	var A edwards25519.ExtendedGroupElement
	if !A.FromBytes(publicKey) {
		return false
	}

	h := sha512.New()
	h.Write(sig[:32])
	h.Write(publicKey[:])
	h.Write(message)
	var digest [64]byte
	h.Sum(digest[:0])

	var hReduced [32]byte
	edwards25519.ScReduce(&hReduced, &digest)

	var R edwards25519.ProjectiveGroupElement
	var b [32]byte
	copy(b[:], sig[32:])
	edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)

	var checkR [32]byte
	R.ToBytes(&checkR)
	return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1
}
Beispiel #19
0
func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
	if len(encrypted) < aes.BlockSize+sha256.Size {
		return nil, false
	}

	iv := encrypted[:aes.BlockSize]
	macBytes := encrypted[len(encrypted)-sha256.Size:]

	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
	mac.Write(encrypted[:len(encrypted)-sha256.Size])
	expected := mac.Sum(nil)

	if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
		return nil, false
	}

	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
	if err != nil {
		return nil, false
	}
	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
	plaintext := make([]byte, len(ciphertext))
	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)

	state := new(sessionState)
	ok := state.unmarshal(plaintext)
	return state, ok
}
Beispiel #20
0
// ListNeighs lists the public keys of the neighbors of the node
func (clnt *Client) ListNeighs() ([]natrium.EdDSAPublic, error) {
	req := textprot.TextReq{
		Verb: "NEIGH_LIST",
	}
	resp, err := clnt.execCmd(req)
	var ninf textprot.NeighInfo
	err = ninf.FromString(resp.Blob)
	if err != nil {
		clnt.sok.Close()
		return nil, ErrBadSocket
	}
	// do the checks
	pubkey := directory.DefaultProvider("").PublicKey()
	err = pubkey.Verify(ninf.Json.HashValue(), ninf.Signat)
	if err != nil {
		clnt.sok.Close() // this server is really bad, go away now
		return nil, ErrBadCrypto
	}
	if ninf.Json.Expires < int(time.Now().Unix()) ||
		subtle.ConstantTimeCompare(clnt.CurrentPublic(), ninf.Json.IssuedTo) != 1 {
		clnt.sok.Close()
		return nil, ErrBadCrypto
	}
	// return the val
	var toret []natrium.EdDSAPublic
	for _, v := range ninf.Json.NeighList {
		toret = append(toret, natrium.EdDSAPublic(v))
	}
	return toret, nil
}
Beispiel #21
0
// compareStrings compares two strings in constant time.
func compareStrings(a, b string) bool {
	if len(a) != len(b) {
		return false
	}

	return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}
Beispiel #22
0
func (c *Crypter) DecryptBox(ciphertext []byte, kdfNum uint8) ([]byte, error) {
	if len(c.ChainVar) == 0 {
		c.ChainVar = make([]byte, CVLen)
	}

	ephPubKey := ciphertext[:c.Cipher.DHLen()]
	dh1 := c.Cipher.DH(c.Key.Private, ephPubKey)
	cv1, cc1 := c.deriveKey(dh1, c.ChainVar, kdfNum)

	header := ciphertext[:(2*c.Cipher.DHLen())+c.Cipher.MACLen()]
	ciphertext = ciphertext[len(header):]
	senderPubKey, err := c.cipher(cc1).Decrypt(header[c.Cipher.DHLen():], append(c.Key.Public, ephPubKey...))
	if err != nil {
		return nil, err
	}
	if len(c.PeerKey.Public) > 0 {
		if len(c.PeerKey.Public) != len(senderPubKey) || subtle.ConstantTimeCompare(senderPubKey, c.PeerKey.Public) != 1 {
			return nil, errors.New("pipe: unexpected sender public key")
		}
	}

	dh2 := c.Cipher.DH(c.Key.Private, senderPubKey)
	cv2, cc2 := c.deriveKey(dh2, cv1, kdfNum+1)
	c.ChainVar = cv2
	body, err := c.cipher(cc2).Decrypt(ciphertext, append(c.Key.Public, header...))
	if err != nil {
		return nil, err
	}
	padLen := int(binary.BigEndian.Uint32(body[len(body)-4:]))

	return body[:len(body)-(padLen+4)], nil
}
Beispiel #23
0
// VerifyMAC verifies the MAC is valid with ConstantTimeCompare.
func VerifyMAC(h hash.Hash, value []byte, mac []byte) error {
	m := CreateMAC(h, value)
	if subtle.ConstantTimeCompare(mac, m) == 1 {
		return nil
	}
	return fmt.Errorf("Invalid MAC:%s", string(m))
}
Beispiel #24
0
// ReadPubEK reads the public part of the endorsement key when no owner is
// established.
func ReadPubEK(f *os.File) ([]byte, error) {
	var n nonce
	if _, err := rand.Read(n[:]); err != nil {
		return nil, err
	}

	pk, d, _, err := readPubEK(f, n)
	if err != nil {
		return nil, err
	}

	// Recompute the hash of the pk and the nonce to defend against replay
	// attacks.
	b, err := pack([]interface{}{pk, n})
	if err != nil {
		return nil, err
	}

	s := sha1.Sum(b)
	if subtle.ConstantTimeCompare(s[:], d[:]) != 1 {
		return nil, errors.New("the ReadPubEK operation failed the replay check")
	}

	return pack([]interface{}{pk})
}
Beispiel #25
0
func (hs *clientHandshakeState) readFinished(out []byte) error {
	c := hs.c

	c.readRecord(recordTypeChangeCipherSpec)
	if err := c.in.error(); err != nil {
		return err
	}

	msg, err := c.readHandshake()
	if err != nil {
		return err
	}
	serverFinished, ok := msg.(*finishedMsg)
	if !ok {
		c.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(serverFinished, msg)
	}

	verify := hs.finishedHash.serverSum(hs.masterSecret)
	if len(verify) != len(serverFinished.verifyData) ||
		subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
		c.sendAlert(alertHandshakeFailure)
		return errors.New("tls: server's Finished message was incorrect")
	}
	hs.finishedHash.Write(serverFinished.marshal())
	copy(out, verify)
	return nil
}
Beispiel #26
0
// Determine if a token is valid.
func (r *HawkRequest) isValid(cfg config.ValkyrieConfig) error {
	// Get credentials from config
	secKey, algo, err := cfg.GetCredentials(r.Id, authScheme)
	if err != nil {
		return err
	}
	// Get opts from config
	host, port, offset, skew, err := cfg.GetOpts()
	if err != nil {
		return err
	}
	// Calc/verify MAC
	normalized := r.normalizedString("header", r.Method, host, port)
	if subtle.ConstantTimeCompare(r.Mac, macHash(algo, secKey, normalized)) != 1 {
		return errors.New("Invalid MAC")
	}
	// Check nonce
	ok, err := cfg.StoreNonce(r.Id, r.Nonce)
	if !ok || err != nil {
		if err == nil {
			err = errors.New("Unable to store nonce; already exists")
		}
		return err
	}
	// Check timestamp
	var tDiff int64
	if tDiff = (time.Now().Unix() - offset) - r.Timestamp; tDiff < 0 {
		tDiff *= -1
	}
	if tDiff > skew {
		return errors.New("Stale timestamp")
	}
	// No errors
	return nil
}
Beispiel #27
0
// VerifySessionKey authenticates a session key.
func (id *Identity) VerifySessionKey(sk *[SessionKeySize]byte) (*[64]byte, bool) {
	peerID := new([ed25519.PublicKeySize]byte)
	keyData := new([64]byte)
	signature := new([ed25519.SignatureSize]byte)
	copy(peerID[:], sk[:])
	copy(keyData[:], sk[ed25519.PublicKeySize:])
	copy(signature[:], sk[blobDataSize:])

	var found bool
	for i := range id.peers {
		if subtle.ConstantTimeCompare(id.peers[i][:], peerID[:]) == 1 {
			found = true
		}
	}

	if !found {
		if id.PeerLookup != nil {
			if !id.PeerLookup(peerID) {
				return nil, false
			}
		} else {
			return nil, false
		}
	}

	if !ed25519.Verify(peerID, sk[:blobDataSize], signature) {
		return nil, false
	}

	return keyData, true
}
Beispiel #28
0
func (r *Runner) httpClusterHandler(w http.ResponseWriter, req *http.Request) {
	authKeyID := strings.SplitN(strings.TrimPrefix(req.URL.Path, "/cluster/"), "/", 2)
	if len(authKeyID[0]) != len(r.authKey) || subtle.ConstantTimeCompare([]byte(authKeyID[0]), []byte(r.authKey)) != 1 {
		w.WriteHeader(401)
		return
	}
	c, ok := r.clusters[authKeyID[1]]
	if !ok {
		http.Error(w, "cluster not found", 404)
		return
	}

	switch req.Method {
	case "GET":
		json.NewEncoder(w).Encode(c)
	case "POST":
		if err := c.AddHost(); err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		w.Write([]byte("ok"))
	case "DELETE":
		hostID := req.FormValue("host")
		if err := c.RemoveHost(hostID); err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		w.Write([]byte("ok"))
	default:
		http.Error(w, "unknown method", 405)
	}
}
Beispiel #29
0
func (a *authReader) checkAuthentication(authcode []byte) bool {
	expectedAuthCode := a.mac.Sum(nil)
	// Truncate at the first 10 bytes
	expectedAuthCode = expectedAuthCode[:10]
	a.auth = subtle.ConstantTimeCompare(expectedAuthCode, authcode) > 0
	return a.auth
}
Beispiel #30
0
// compare securely (constant-time) compares the unmasked token from the request
// against the real token from the session.
func compareTokens(a, b []byte) bool {
	if subtle.ConstantTimeCompare(a, b) == 1 {
		return true
	}

	return false
}