Example #1
0
func (ch *authHSChan) validatePacket(pkt *packet.AuthHSPacket) error {
	nSet := 0
	if msg := pkt.GetProof(); msg != nil {
		nSet++
		if pkDER := msg.GetPublicKey(); pkDER == nil {
			return fmt.Errorf("missing public_key")
		}
		if sig := msg.GetSignature(); sig == nil {
			return fmt.Errorf("missing signature")
		}
	}
	if msg := pkt.GetResult(); msg != nil {
		nSet++
	}
	if nSet != 1 {
		return fmt.Errorf("has %d fields set", nSet)
	}
	return nil
}
Example #2
0
func (ch *authHSChan) onPacketClient(authPkt *packet.AuthHSPacket) error {
	log := ch.conn.endpoint.log
	resultMsg := authPkt.GetResult()
	if resultMsg == nil {
		return fmt.Errorf("missing result")
	}
	if !resultMsg.GetAccepted() {
		ch.conn.endpoint.onRemoteReject(ch.conn.hostname)
		return fmt.Errorf("client: auth to '%s' rejected", ch.conn.hostname)
	}

	isKnown := resultMsg.GetIsKnownContact()
	log.Printf("client: auth to server '%s' accepted isKnown: %v", ch.conn.hostname, isKnown)

	ch.conn.getControlChan().isAuthenticated = true
	ch.conn.getControlChan().isKnownToPeer = isKnown
	ch.conn.authTimer.Stop() // Stop the f**k().
	ch.conn.setEstablished()

	// XXX: Send a channel close?  This is something the server ought to be
	// doing, so don't bother for now.  This code will not use this channel
	// past this point, apart from processing the server's close.

	if isKnown {
		ch.conn.endpoint.onConnectionEstablished(ch.conn)
		return nil
	}

	// The peer doesn't immediately recognize us. If this is expected,
	// dispatch a ContactRequest, otherwise, we got removed.
	requestData := ch.conn.endpoint.requestData(ch.conn.hostname)
	if requestData == nil {
		ch.conn.endpoint.onRemoteReject(ch.conn.hostname)
		return fmt.Errorf("client: remote peer remove us from contacts")
	}
	return newClientContactReqChan(ch.conn, requestData)
}
Example #3
0
func (ch *authHSChan) onPacketServer(authPkt *packet.AuthHSPacket) error {
	log := ch.conn.endpoint.log
	proofMsg := authPkt.GetProof()
	if proofMsg == nil {
		return fmt.Errorf("missing proof")
	}

	// Decode and validate the public key.
	pk, rest, err := pkcs1.DecodePublicKeyDER(proofMsg.GetPublicKey())
	if err != nil {
		return err
	} else if rest != nil && len(rest) > 0 {
		return fmt.Errorf("trailing garbage present after public key")
	} else if pk.N.BitLen() != authHiddenServicePublicKeyBits {
		return fmt.Errorf("invalid public modulus size: %d", pk.N.BitLen())
	}

	// Calculate the client hostname.
	clientHostname, err := pkcs1.OnionAddr(pk)
	if err != nil {
		return err
	}

	sigOk, isKnown := false, false

	// Note: The reference implementation checks against the hostname
	// blacklist for rejected peers, and early rejects clients durring
	// the authentication phase by closing the connection.
	//
	// This is a bit rude.  Check the blacklist and send a rejected
	// response, then close the connection (Done by virtue of returning
	// an error).
	if !ch.conn.endpoint.isBlacklisted(clientHostname) {
		// Calculate the proof.
		proof := ch.calculateProof(clientHostname, ch.conn.endpoint.hostname)

		// Verify proof.
		//
		// The spec neglects to mention PKCS #1 v1.5/SHA256.  Also, not
		// SHA256 suming proof is deliberate because the ricochet code
		// doesn't bother hashing the proof.
		sig := proofMsg.GetSignature()
		err = rsa.VerifyPKCS1v15(pk, crypto.SHA256, proof, sig)
		if err == nil {
			sigOk = true
			ch.conn.getControlChan().isAuthenticated = true
			ch.conn.getControlChan().isKnownToPeer = true
			ch.conn.hostname = clientHostname
			isKnown = ch.conn.endpoint.isKnown(clientHostname)
		}
	} else {
		err = fmt.Errorf("auth from blacklisted peer: '%v'", clientHostname)
	}

	log.Printf("server: auth from client '%s' accepted: %v", clientHostname, sigOk)

	//  Send the result to the client.
	if wrErr := ch.sendResult(sigOk, isKnown); wrErr != nil {
		return wrErr
	}

	if sigOk {
		ch.conn.setEstablished()
		if isKnown {
			ch.conn.authTimer.Stop()
			ch.conn.endpoint.onConnectionEstablished(ch.conn)
		} else {
			// Give them another interval to request contact.
			ch.conn.authTimer.Reset(authenticationTimeout)
		}
	}

	// Close the authentication channel.
	if wrErr := ch.conn.sendChanClose(ch.chanID); wrErr != nil {
		return wrErr
	}
	return err
}