// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package osp // TODO(pthatcher): // - avoid NetworkIdleTimeout // - make a client object that can send and receive more than one stream // - make a server object that can send and receive more than one stream import ( "context" "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "encoding/pem" "fmt" "io" "log" "math/big" quic "github.com/lucas-clemente/quic-go" ) func GenerateTlsCert() (*tls.Certificate, error) { key, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { return nil, err } template := x509.Certificate{SerialNumber: big.NewInt(1)} certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) if err != nil { return nil, err } keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) if err != nil { return nil, err } return &tlsCert, nil } func readAllStreams(ctx context.Context, session quic.Session, streams chan<- io.ReadWriteCloser) { for !done(ctx) { stream, err := session.AcceptStream() if err != nil && !done(ctx) { log.Println("Failed to accept stream with QUIC", err.Error()) } streams <- stream } } // Returns a quic.Session object with a .OpenStreamSync method to send streams func DialAsQuicClient(ctx context.Context, hostname string, port int) (quic.Session, error) { // TODO(pthatcher): Change InsecureSkipVerify tlsConfig := &tls.Config{InsecureSkipVerify: true} addr := fmt.Sprintf("%s:%d", hostname, port) session, err := quic.DialAddrContext(ctx, addr, tlsConfig, nil) return session, err } // Reads in streams func RunQuicServer(ctx context.Context, port int, cert tls.Certificate, streams chan<- io.ReadWriteCloser) error { addr := fmt.Sprintf(":%d", port) tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}} listener, err := quic.ListenAddr(addr, tlsConfig, nil) if err != nil { return err } go func() { waitUntilDone(ctx) listener.Close() }() for { session, err := listener.Accept() if err != nil && !done(ctx) { log.Println("Failed to accept session with QUIC:", err.Error()) } go readAllStreams(ctx, session, streams) } }