// NewEndpoint creates a Ricochet client/server endpoint with the provided // configuration, including registering the ephemeral HS with Tor. func NewEndpoint(cfg *EndpointConfig) (e *Endpoint, err error) { e = new(Endpoint) e.hostname, _ = pkcs1.OnionAddr(&cfg.PrivateKey.PublicKey) e.privateKey = cfg.PrivateKey e.ctrl = cfg.TorControlPort e.isoBase, err = getIsolationAuth() if err != nil { return nil, err } e.outgoingQueue = channels.NewInfiniteChannel() e.eventQueue = channels.NewInfiniteChannel() e.pendingContacts = make(map[string]*ricochetContact) e.EventChan = e.eventQueue.Out() e.blacklist = make(map[string]bool) for _, id := range cfg.BlacklistedContacts { if err := e.BlacklistContact(id, true); err != nil { return nil, err } } e.contacts = make(map[string]*ricochetContact) for _, id := range cfg.KnownContacts { if err := e.AddContact(id, nil); err != nil { return nil, err } } for id, requestData := range cfg.PendingContacts { if err := e.AddContact(id, requestData); err != nil { return nil, err } } e.ln, err = e.ctrl.Listener(ricochetPort, e.privateKey) if err != nil { return nil, err } logWr := cfg.LogWriter if logWr == nil { logWr = ioutil.Discard } e.log = golog.New(logWr, "", golog.LstdFlags) e.log.Printf("server: online as '%v'", e.hostname) go e.hsAcceptWorker() go e.hsConnectWorker() return e, nil }
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 }