Exemplo n.º 1
0
// Validates incoming connection client certificates,
// and identifies the node they are associated with,
// then sends the new connection to that node to handle.
func acceptIncoming(ch <-chan *tls.Conn) {
	for {
		conn := <-ch

		state := conn.ConnectionState()
		if len(state.PeerCertificates) == 0 {
			conn.Close()
			continue
		}

		cert := state.PeerCertificates[0]

		// Find the node this connection is from.
		matched := false
		for _, node := range logic.Nodes {
			if node == logic.Me {
				continue
			}

			var verifyOpts x509.VerifyOptions
			verifyOpts.Intermediates = new(x509.CertPool)
			verifyOpts.Roots = node.Cert
			chains, err := cert.Verify(verifyOpts)
			if err != nil {
				continue
			}

			if len(chains) > 0 {
				matched = true
				node.NewConn <- conn
				break
			}
		}

		// No matching node found. Close the connection.
		if !matched {
			conn.Close()
		}
	}
}
Exemplo n.º 2
0
func main() {
	app := cli.NewApp()
	app.Name = "gen-ct-bundle"
	app.Version = fmt.Sprintf("0.1.0 [%s]", core.GetBuildID())

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "config",
			Value:  "config.json",
			EnvVar: "BOULDER_CONFIG",
			Usage:  "Path to Boulder JSON configuration file",
		},
		cli.StringSliceFlag{
			Name:  "cert",
			Value: &cli.StringSlice{},
			Usage: "Paths to PEM certificates in order from issuer -> root",
		},
		cli.StringFlag{
			Name:  "out",
			Usage: "Path to write out the DER certificate bundle",
		},
	}

	app.Action = func(c *cli.Context) {
		bundleFilename := c.GlobalString("out")
		if bundleFilename == "" {
			fmt.Fprintf(os.Stderr, "-out flag is required\n")
			os.Exit(1)
		}
		fmt.Println(bundleFilename)

		configFileName := c.GlobalString("config")
		configJSON, err := ioutil.ReadFile(configFileName)
		cmd.FailOnError(err, "Unable to read config file")

		var config cmd.Config
		err = json.Unmarshal(configJSON, &config)
		cmd.FailOnError(err, "Failed to read configuration")

		if config.Publisher.CT == nil {
			fmt.Fprintf(os.Stderr, "Publisher CT configuration required to assemble correct root pool\n")
			os.Exit(1)
		}

		certFilenames := c.GlobalStringSlice("cert")
		if len(certFilenames) == 0 {
			//
		}
		var chain []*x509.Certificate
		for _, certFilename := range certFilenames {
			cert, err := core.LoadCert(certFilename)
			cmd.FailOnError(err, fmt.Sprintf("Failed to load certificate (%s)", certFilename))
			chain = append(chain, cert)
		}

		roots := x509.NewCertPool()
		roots.AddCert(chain[len(chain)-1])
		opts := x509.VerifyOptions{Roots: roots}

		if len(chain) > 2 {
			inters := x509.NewCertPool()
			for _, inter := range chain[1 : len(chain)-1] {
				inters.AddCert(inter)
			}
			opts.Intermediates = inters
		}
		_, err = chain[0].Verify(opts)
		cmd.FailOnError(err, "Failed to load chain")

		client := http.Client{}
		maxLen := 0
		for _, ctLog := range config.Publisher.CT.Logs {
			fmt.Printf("# %s\n", ctLog.URI)
			logRoots, err := downloadCTRootList(&client, ctLog.URI)
			cmd.FailOnError(err, "Failed to retrieve root certificates")
			ctPool := x509.NewCertPool()
			for _, root := range logRoots {
				ctPool.AddCert(root)
			}
			ctOpts := x509.VerifyOptions{Roots: ctPool}
			var lastValidChain []*x509.Certificate
			fmt.Println("\tTesting chain validity with downloaded log root pool")
			for i := range chain {
				if len(chain)-i > 1 {
					ctOpts.Intermediates = x509.NewCertPool()
					for _, inter := range chain[1 : len(chain)-i] {
						ctOpts.Intermediates.AddCert(inter)
					}
				} else {
					ctOpts.Intermediates = nil
				}
				fmt.Printf("\t\t%s -> constructed root pool", prettyChain(chain[:len(chain)-i]))
				if _, err := chain[0].Verify(ctOpts); err != nil {
					fmt.Println(": Invalid!")
					break
				}
				fmt.Println(": Valid!")
				lastValidChain = chain[:len(chain)-i]
			}
			if len(lastValidChain) == 0 {
				fmt.Println("\n\t!! Couldn't construct any valid chains, this may mean you haven't   !!")
				fmt.Println("\t!! provided the full chain or that this CT log doesn't contain a    !!")
				fmt.Println("\t!! root certificates that chain those provided. In the case of the  !!")
				fmt.Println("\t!! latter you should remove this log from your configuration since  !!")
				fmt.Println("\t!! your submissions will fail and be discarded.                     !!")
				continue
			}
			fmt.Printf("\n\tBundle size for %s: %d\n", ctLog.URI, len(lastValidChain))
			if len(lastValidChain) > maxLen {
				maxLen = len(lastValidChain)
			}
		}

		if maxLen == 0 {
			fmt.Println("\n!! Couldn't find any valid chains for configured logs, this may     !!")
			fmt.Println("!! mean you haven't provided the full chain or that this CT log     !!")
			fmt.Println("!! doesn't contain a root certificates that chain those provided.   !!")
			fmt.Println("!! The bundle will still be written out but you should only use     !!")
			fmt.Println("!! this if you really know what you are doing!                      !!")
			maxLen = len(chain)
		}
		fmt.Printf("\n# Shared bundle size: %d certificates, %s\n", maxLen, prettyChain(chain[:maxLen]))

		// Write bundle out
		f, err := os.Create(bundleFilename)
		cmd.FailOnError(err, fmt.Sprintf("Failed to create submission bundle (%s)", bundleFilename))
		defer f.Close()

		for _, cert := range chain[:maxLen] {
			f.Write(cert.Raw)
		}
		fmt.Printf("# CT submission bundle has been written to %s\n", bundleFilename)
	}

	err := app.Run(os.Args)
	cmd.FailOnError(err, "Failed to run application")
}
Exemplo n.º 3
0
// Blocks listening for connections of that given protocol type,
// and calls the specified handler when one is received,
// passing the node ID of the connecting node, or 0 for the Client Protocol.
func Listen(protocol int, handler func(id uint16, b *BaseConn)) {

	ip := config.NodeIP(config.Id())
	ipStr := ip.String()
	port := getProtocolPort(protocol)
	portStr := strconv.FormatInt(int64(port), 10)

	tlsConfig := new(tls.Config)
	tlsConfig.Certificates = []tls.Certificate{*config.Certificate()}
	if protocol != CLIENT_PROTOCOL {
		tlsConfig.ClientAuth = tls.RequireAnyClientCert
	}

	listener, err := tls.Listen("tcp", ipStr+":"+portStr, tlsConfig)
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}
		tlsConn := conn.(*tls.Conn)

		err = tlsConn.Handshake()
		if err != nil {
			tlsConn.Close()
			continue
		}

		if protocol != CLIENT_PROTOCOL {
			// Check this connecting node has authenticated.
			state := tlsConn.ConnectionState()
			if len(state.PeerCertificates) == 0 {
				tlsConn.Close()
				continue
			}
			cert := state.PeerCertificates[0]

			// Identify which node they authenticated as.
			matched := false
			for _, node := range config.Nodes() {
				var verifyOpts x509.VerifyOptions
				verifyOpts.Intermediates = new(x509.CertPool)
				verifyOpts.Roots = config.NodeCertPool(node)
				chains, err := cert.Verify(verifyOpts)
				if err != nil {
					continue
				}

				// Matched the node. Start the handler.
				if len(chains) > 0 {
					matched = true
					go handler(node, newBaseConn(tlsConn))
					break
				}
			}

			// No matching node found. Close the connection.
			if !matched {
				tlsConn.Close()
			}
		} else {
			// We don't authenticate clients.
			// Just run the handler.
			handler(0, newBaseConn(tlsConn))
		}
	}
}