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.
This commit is contained in:
nemunaire 2018-02-02 20:29:16 +01:00
parent 3ed8c619b1
commit 68e5c4cd2b
5 changed files with 37 additions and 18 deletions

View File

@ -1,11 +1,12 @@
package api package api
import ( import (
"crypto/rand"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math/rand"
"io/ioutil" "io/ioutil"
"math/big"
"os" "os"
"path" "path"
"time" "time"
@ -87,10 +88,19 @@ func getTeamP12File(cert fic.Certificate, _ []byte) (interface{}, error) {
func generateClientCert(_ httprouter.Params, _ []byte) (interface{}, error) { func generateClientCert(_ httprouter.Params, _ []byte) (interface{}, error) {
// First, generate a new, unique, serial // First, generate a new, unique, serial
serial := rand.Int63() var serial_gen [8]byte
for fic.ExistingCertSerial(serial) { if _, err := rand.Read(serial_gen[:]); err != nil {
serial = rand.Int63() 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 // Let's pick a random password
password, err := pki.GeneratePassword() 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 // moreover, backend doesn't update the DB at registration, it only creates a symlink
cert.IdTeam = uc.Team 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 { if uc.Team != nil {
srcLinkPath := fmt.Sprintf("%d", *uc.Team) srcLinkPath := fmt.Sprintf("%d", *uc.Team)

View File

@ -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) { func certificateHandler(f func(fic.Certificate,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
return func (ps httprouter.Params, body []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 return nil, err
} else if cert, err := fic.GetCertificate(certid); err != nil { } else if cert, err := fic.GetCertificate(certid); err != nil {
return nil, err return nil, err

View File

@ -13,21 +13,23 @@ import (
"time" "time"
) )
func ClientCertificatePath(serial int64) string { func ClientCertificatePath(serial uint64) string {
return path.Join(PKIDir, fmt.Sprintf("%d", serial), "cert.pem") 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") 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") 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{ client := &x509.Certificate{
SerialNumber: big.NewInt(serial), SerialNumber: &certid,
Subject: pkix.Name{ Subject: pkix.Name{
Organization: []string{"EPITA"}, Organization: []string{"EPITA"},
OrganizationalUnit: []string{"SRS laboratory"}, OrganizationalUnit: []string{"SRS laboratory"},
@ -69,7 +71,7 @@ func GenerateClient(serial int64, notBefore time.Time, notAfter time.Time, paren
return nil return nil
} }
func WriteP12(serial int64, password string) error { func WriteP12(serial uint64, password string) error {
cmd := exec.Command("/usr/bin/openssl", "pkcs12", "-export", cmd := exec.Command("/usr/bin/openssl", "pkcs12", "-export",
"-inkey", ClientPrivkeyPath(serial), "-inkey", ClientPrivkeyPath(serial),
"-in", ClientCertificatePath(serial), "-in", ClientCertificatePath(serial),

View File

@ -2,11 +2,12 @@ package fic
import ( import (
"database/sql" "database/sql"
"math/big"
"time" "time"
) )
type Certificate struct { type Certificate struct {
Id int64 `json:"id,string"` Id uint64 `json:"id,string"`
Creation time.Time `json:"creation"` Creation time.Time `json:"creation"`
Password string `json:"password"` Password string `json:"password"`
IdTeam *int64 `json:"id_team"` IdTeam *int64 `json:"id_team"`
@ -49,17 +50,20 @@ func GetTeamCertificates(team Team) (certificates []Certificate, err error) {
return 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) 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 return
} }
func ExistingCertSerial(serial int64) (bool) { func ExistingCertSerial(serial [8]byte) (bool) {
c, _ := GetCertificate(serial) var m big.Int
m.SetBytes(serial[:])
c, _ := GetCertificate(m.Uint64())
return c.Id > 0 return c.Id > 0
} }
func RegisterCertificate(serial int64, password string) (Certificate, error) { func RegisterCertificate(serial uint64, password string) (Certificate, error) {
now := time.Now() now := time.Now()
if _, err := DBExec("INSERT INTO certificates (id_cert, creation, password) VALUES (?, ?, ?)", serial, now, password); err != nil { if _, err := DBExec("INSERT INTO certificates (id_cert, creation, password) VALUES (?, ?, ?)", serial, now, password); err != nil {
return Certificate{}, err return Certificate{}, err

View File

@ -84,7 +84,7 @@ CREATE TABLE IF NOT EXISTS teams(
} }
if _, err := db.Exec(` if _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS certificates( 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, creation TIMESTAMP NOT NULL,
password VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL,
id_team INTEGER NULL, id_team INTEGER NULL,