Skip to content

Commit

Permalink
Merge pull request #26 from ninedraft/test-certs
Browse files Browse the repository at this point in the history
  • Loading branch information
ninedraft committed Oct 2, 2022
2 parents fb52392 + 88ee83c commit 06d711b
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 16 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.17.x]
go-version: [1.18.x, 1.19.*]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -25,7 +25,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.16.x
go-version: 1.19.x
- name: Checkout code
uses: actions/checkout@v2
- name: Test
Expand Down
115 changes: 115 additions & 0 deletions cmd/gencert/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package main

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"flag"
"fmt"
"log"
"math/big"
"os"
"strings"
"time"
)

const (
keySize = 4096
dateFormat = "2006-01-02"
)

func main() {
keyOut := "key.pem"
flag.StringVar(&keyOut, "key", keyOut, "dst file to write private key")

certOut := "cert.pem"
flag.StringVar(&certOut, "cert.pem", certOut, "dst file to write certificate")

var dnsNames []string
flag.Func("dns", "DNS records for cert", func(name string) error {
if strings.TrimSpace(name) == "" {
return nil
}
dnsNames = append(dnsNames, name)
return nil
})

organization := "dev"
flag.StringVar(&organization, "org", organization, "organization which generates the certificate")

country := "OO"
flag.StringVar(&country, "country", country, "country of certificate emitter")

locality := "ether"
flag.StringVar(&locality, "loc", locality, "locality of certificate emitter")

expiration := time.Now().AddDate(32, 0, 0)
flag.Func("exp",
"certificate expiration date. Format: "+dateFormat+". Default: "+expiration.Format(dateFormat),
func(value string) error {
t, errParse := time.Parse(value, dateFormat)
if errParse != nil {
return errParse
}
expiration = t
return nil
})
flag.Parse()

log.Print("generating private key")
privKey, errKey := rsa.GenerateKey(rand.Reader, keySize)
if errKey != nil {
panic(errKey)
}

certTemplate := &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{organization},
Country: []string{country},
Locality: []string{locality},
},
DNSNames: dnsNames,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
IsCA: false,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}

log.Print("generating certificate")
certEncoded, errCert := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, &privKey.PublicKey, privKey)
if errCert != nil {
panic(errCert)
}
keyEncoded := x509.MarshalPKCS1PrivateKey(privKey)

log.Print("writing key and certificate data")
if err := writePEM(keyOut, "RSA PRIVATE KEY", keyEncoded); err != nil {
panic(err)
}
if err := writePEM(certOut, "CERTIFICATE", certEncoded); err != nil {
panic(err)
}
}

func writePEM(file, name string, data []byte) error {
// #nosec G304 // hardcoded in code
f, errCreate := os.Create(file)
if errCreate != nil {
return fmt.Errorf("creating file: %w", errCreate)
}
defer func() { _ = f.Close() }()

errEncode := pem.Encode(f, &pem.Block{
Type: name,
Bytes: data,
})
if errEncode != nil {
return fmt.Errorf("encoding PEM data: %w", errEncode)
}
return nil
}
14 changes: 7 additions & 7 deletions gemax/mime.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ package gemax
//
// Valid values for the "lang" parameter are comma-separated lists of one or
// more language tags as defined in RFC4646. For example:
// * "text/gemini; lang=en" Denotes a text/gemini document written in English
// * "text/gemini; lang=fr" Denotes a text/gemini document written in French
// * "text/gemini; lang=en,fr" Denotes a text/gemini document written in a mixture of English and French
// * "text/gemini; lang=de-CH" Denotes a text/gemini document written in Swiss German
// * "text/gemini; lang=sr-Cyrl" Denotes a text/gemini document written in Serbian using the Cyrllic script
// * "text/gemini; lang=zh-Hans-CN" Denotes a text/gemini document written in Chinese using
// the Simplified script as used in mainland China
// - "text/gemini; lang=en" Denotes a text/gemini document written in English
// - "text/gemini; lang=fr" Denotes a text/gemini document written in French
// - "text/gemini; lang=en,fr" Denotes a text/gemini document written in a mixture of English and French
// - "text/gemini; lang=de-CH" Denotes a text/gemini document written in Swiss German
// - "text/gemini; lang=sr-Cyrl" Denotes a text/gemini document written in Serbian using the Cyrllic script
// - "text/gemini; lang=zh-Hans-CN" Denotes a text/gemini document written in Chinese using
// the Simplified script as used in mainland China
const MIMEGemtext = "text/gemini"
4 changes: 2 additions & 2 deletions gemax/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestServerCancelListen(test *testing.T) {
var server = &gemax.Server{
Addr: testaddr.Addr(),
Logf: test.Logf,
Handler: func(ctx context.Context, rw gemax.ResponseWriter, req gemax.IncomingRequest) {
Handler: func(_ context.Context, rw gemax.ResponseWriter, _ gemax.IncomingRequest) {
_, _ = io.WriteString(rw, "example text")
},
}
Expand Down Expand Up @@ -102,7 +102,7 @@ func TestListenAndServe(test *testing.T) {
var server = &gemax.Server{
Addr: "localhost:40423",
Logf: test.Logf,
Handler: func(ctx context.Context, rw gemax.ResponseWriter, req gemax.IncomingRequest) {
Handler: func(_ context.Context, rw gemax.ResponseWriter, _ gemax.IncomingRequest) {
_, _ = io.WriteString(rw, "example text")
},
}
Expand Down
12 changes: 7 additions & 5 deletions gemax/server_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import (
// This mechanism can be used as redirect on other protocol pages.
//
// Examples:
// Redirect(rw, req, "gemini://other.server.com/page", status.Redirect)
// Redirect(rw, req, "../root/page", status.PermanentRedirect)
// Redirect(rw, req, "https://wikipedia.org", status.Success)
//
// Redirect(rw, req, "gemini://other.server.com/page", status.Redirect)
// Redirect(rw, req, "../root/page", status.PermanentRedirect)
// Redirect(rw, req, "https://wikipedia.org", status.Success)
func Redirect(rw ResponseWriter, req IncomingRequest, target string, code status.Code) {
if code == status.Success {
rw.WriteStatus(code, MIMEGemtext)
Expand Down Expand Up @@ -67,8 +68,9 @@ func ServeContent(contentType string, content []byte) Handler {
// Query extracts canonical gemini query values
// from url query part. Values are sorted in ascending order.
// Expected values:
// ?query&key=value => [query]
// ?a&b=&key=value => [a, b]
//
// ?query&key=value => [query]
// ?a&b=&key=value => [a, b]
func Query(query urlpkg.Values) []string {
var keys = make([]string, 0, len(query))
for key, values := range query {
Expand Down
1 change: 1 addition & 0 deletions gemax/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func Text(code Code) string {
}

// Comments copy-pasted from official gemini specification.
//
//go:generate stringer -type Code -linecomment -output status_string.go
const (
// Undefined is a default empty status code value.
Expand Down

0 comments on commit 06d711b

Please sign in to comment.