From 68e5c4cd2b9e120967674c464eb95dbd6bd98488 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 2 Feb 2018 20:29:16 +0100 Subject: [PATCH] pki: improve serial number generation + fix team association Replace math/rand by crypto/rand. Fix big when associating certificate with leading zero: nginx prepend 0 wherehas we don't. --- admin/api/certificate.go | 23 ++++++++++++++++++----- admin/api/handlers.go | 2 +- admin/pki/client.go | 14 ++++++++------ libfic/certificate.go | 14 +++++++++----- libfic/db.go | 2 +- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/admin/api/certificate.go b/admin/api/certificate.go index 69e762e2..bfbda073 100644 --- a/admin/api/certificate.go +++ b/admin/api/certificate.go @@ -1,11 +1,12 @@ package api import ( + "crypto/rand" "encoding/json" "errors" "fmt" - "math/rand" "io/ioutil" + "math/big" "os" "path" "time" @@ -87,10 +88,19 @@ func getTeamP12File(cert fic.Certificate, _ []byte) (interface{}, error) { func generateClientCert(_ httprouter.Params, _ []byte) (interface{}, error) { // First, generate a new, unique, serial - serial := rand.Int63() - for fic.ExistingCertSerial(serial) { - serial = rand.Int63() + var serial_gen [8]byte + if _, err := rand.Read(serial_gen[:]); err != nil { + return nil, err } + for fic.ExistingCertSerial(serial_gen) { + if _, err := rand.Read(serial_gen[:]); err != nil { + return nil, err + } + } + + var serial_b big.Int + serial_b.SetBytes(serial_gen[:]) + serial := serial_b.Uint64() // Let's pick a random password password, err := pki.GeneratePassword() @@ -148,7 +158,10 @@ func updateCertificateAssociation(cert fic.Certificate, body []byte) (interface{ // moreover, backend doesn't update the DB at registration, it only creates a symlink cert.IdTeam = uc.Team - dstLinkPath := path.Join(TeamsDir, fmt.Sprintf("_AUTH_ID_%X", cert.Id)) + var serial big.Int + serial.SetUint64(cert.Id) + + dstLinkPath := path.Join(TeamsDir, fmt.Sprintf("_AUTH_ID_%0X", serial.Bytes())) if uc.Team != nil { srcLinkPath := fmt.Sprintf("%d", *uc.Team) diff --git a/admin/api/handlers.go b/admin/api/handlers.go index 8824b567..32fe0cb4 100644 --- a/admin/api/handlers.go +++ b/admin/api/handlers.go @@ -282,7 +282,7 @@ func fileHandler(f func(fic.EFile,[]byte) (interface{}, error)) func (httprouter func certificateHandler(f func(fic.Certificate,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) { - if certid, err := strconv.ParseInt(string(ps.ByName("certid")), 10, 64); err != nil { + if certid, err := strconv.ParseUint(string(ps.ByName("certid")), 10, 64); err != nil { return nil, err } else if cert, err := fic.GetCertificate(certid); err != nil { return nil, err diff --git a/admin/pki/client.go b/admin/pki/client.go index 40c2ff47..011d945c 100644 --- a/admin/pki/client.go +++ b/admin/pki/client.go @@ -13,21 +13,23 @@ import ( "time" ) -func ClientCertificatePath(serial int64) string { +func ClientCertificatePath(serial uint64) string { return path.Join(PKIDir, fmt.Sprintf("%d", serial), "cert.pem") } -func ClientPrivkeyPath(serial int64) string { +func ClientPrivkeyPath(serial uint64) string { return path.Join(PKIDir, fmt.Sprintf("%d", serial), "privkey.pem") } -func ClientP12Path(serial int64) string { +func ClientP12Path(serial uint64) string { return path.Join(PKIDir, fmt.Sprintf("%d", serial), "team.p12") } -func GenerateClient(serial int64, notBefore time.Time, notAfter time.Time, parent_cert *x509.Certificate, parent_priv *ecdsa.PrivateKey) error { +func GenerateClient(serial uint64, notBefore time.Time, notAfter time.Time, parent_cert *x509.Certificate, parent_priv *ecdsa.PrivateKey) error { + var certid big.Int + certid.SetUint64(serial) client := &x509.Certificate{ - SerialNumber: big.NewInt(serial), + SerialNumber: &certid, Subject: pkix.Name{ Organization: []string{"EPITA"}, OrganizationalUnit: []string{"SRS laboratory"}, @@ -69,7 +71,7 @@ func GenerateClient(serial int64, notBefore time.Time, notAfter time.Time, paren return nil } -func WriteP12(serial int64, password string) error { +func WriteP12(serial uint64, password string) error { cmd := exec.Command("/usr/bin/openssl", "pkcs12", "-export", "-inkey", ClientPrivkeyPath(serial), "-in", ClientCertificatePath(serial), diff --git a/libfic/certificate.go b/libfic/certificate.go index cce949aa..28348d48 100644 --- a/libfic/certificate.go +++ b/libfic/certificate.go @@ -2,11 +2,12 @@ package fic import ( "database/sql" + "math/big" "time" ) type Certificate struct { - Id int64 `json:"id,string"` + Id uint64 `json:"id,string"` Creation time.Time `json:"creation"` Password string `json:"password"` IdTeam *int64 `json:"id_team"` @@ -49,17 +50,20 @@ func GetTeamCertificates(team Team) (certificates []Certificate, err error) { return } -func GetCertificate(serial int64) (c Certificate, err error) { +func GetCertificate(serial uint64) (c Certificate, err error) { err = DBQueryRow("SELECT id_cert, creation, password, id_team, revoked FROM certificates WHERE id_cert = ?", serial).Scan(&c.Id, &c.Creation, &c.Password, &c.IdTeam, &c.Revoked) return } -func ExistingCertSerial(serial int64) (bool) { - c, _ := GetCertificate(serial) +func ExistingCertSerial(serial [8]byte) (bool) { + var m big.Int + m.SetBytes(serial[:]) + + c, _ := GetCertificate(m.Uint64()) return c.Id > 0 } -func RegisterCertificate(serial int64, password string) (Certificate, error) { +func RegisterCertificate(serial uint64, password string) (Certificate, error) { now := time.Now() if _, err := DBExec("INSERT INTO certificates (id_cert, creation, password) VALUES (?, ?, ?)", serial, now, password); err != nil { return Certificate{}, err diff --git a/libfic/db.go b/libfic/db.go index c6d6bfca..aa797c97 100644 --- a/libfic/db.go +++ b/libfic/db.go @@ -84,7 +84,7 @@ CREATE TABLE IF NOT EXISTS teams( } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS certificates( - id_cert BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, + id_cert BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, creation TIMESTAMP NOT NULL, password VARCHAR(255) NOT NULL, id_team INTEGER NULL,