1// Copyright 2018 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package osp 6 7// TODO(jophba): 8// - avoid NetworkIdleTimeout 9// - make a client object that can send and receive more than one stream 10// - make a server object that can send and receive more than one stream 11 12import ( 13 "context" 14 "crypto/rand" 15 "crypto/rsa" 16 "crypto/tls" 17 "crypto/x509" 18 "encoding/pem" 19 "fmt" 20 "io" 21 "log" 22 "math/big" 23 24 quic "github.com/lucas-clemente/quic-go" 25) 26 27func GenerateTlsCert() (*tls.Certificate, error) { 28 key, err := rsa.GenerateKey(rand.Reader, 1024) 29 if err != nil { 30 return nil, err 31 } 32 template := x509.Certificate{SerialNumber: big.NewInt(1)} 33 certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) 34 if err != nil { 35 return nil, err 36 } 37 keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 38 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 39 40 tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) 41 if err != nil { 42 return nil, err 43 } 44 return &tlsCert, nil 45} 46 47func readAllStreams(ctx context.Context, session quic.Session, streams chan<- io.ReadWriteCloser) { 48 for !done(ctx) { 49 stream, err := session.AcceptStream() 50 if err != nil && !done(ctx) { 51 log.Println("Failed to accept stream with QUIC", err.Error()) 52 } 53 streams <- stream 54 } 55} 56 57// Returns a quic.Session object with a .OpenStreamSync method to send streams 58func DialAsQuicClient(ctx context.Context, hostname string, port int) (quic.Session, error) { 59 // TODO(jophba): Change InsecureSkipVerify 60 tlsConfig := &tls.Config{InsecureSkipVerify: true} 61 addr := fmt.Sprintf("%s:%d", hostname, port) 62 session, err := quic.DialAddrContext(ctx, addr, tlsConfig, nil) 63 return session, err 64} 65 66// Reads in streams 67func RunQuicServer(ctx context.Context, port int, cert tls.Certificate, streams chan<- io.ReadWriteCloser) error { 68 addr := fmt.Sprintf(":%d", port) 69 tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}} 70 listener, err := quic.ListenAddr(addr, tlsConfig, nil) 71 if err != nil { 72 return err 73 } 74 go func() { 75 waitUntilDone(ctx) 76 listener.Close() 77 }() 78 for { 79 session, err := listener.Accept() 80 if err != nil && !done(ctx) { 81 log.Println("Failed to accept session with QUIC:", err.Error()) 82 } 83 go readAllStreams(ctx, session, streams) 84 } 85} 86