package fic import ( "database/sql" "math/big" "time" ) // Certificate represents a client certificate, which can be associated to a team. // // This is one method usable to handle authentication. // To use it in nginx, you'll need to add following lines in your configuration: // // ssl_client_certificate PKI/shared/ca.pem; // ssl_trusted_certificate PKI/shared/ca.pem; // ssl_verify_client optional; // // Non-recognized clients will have access to a registration form. type Certificate struct { Id uint64 `json:"id,string"` Creation time.Time `json:"creation"` Password string `json:"password"` Revoked *time.Time `json:"revoked"` } // GetCertificates returns the list of all generated certificates. func GetCertificates() (certificates []Certificate, err error) { var rows *sql.Rows if rows, err = DBQuery("SELECT id_cert, creation, password, revoked FROM certificates ORDER BY creation"); err == nil { defer rows.Close() certificates = make([]Certificate, 0) for rows.Next() { var c Certificate if err = rows.Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked); err != nil { return } certificates = append(certificates, c) } err = rows.Err() } return } // GetCertificate retrieves a certificate from its serial number. func GetCertificate(serial uint64) (c Certificate, err error) { err = DBQueryRow("SELECT id_cert, creation, password, revoked FROM certificates WHERE id_cert = ?", serial).Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked) return } // ExistingCertSerial tells you if the given bytes correspond to a know certificate. func ExistingCertSerial(serial [8]byte) bool { var m big.Int m.SetBytes(serial[:]) c, _ := GetCertificate(m.Uint64()) return c.Id > 0 } // RegisterCertificate registers a certificate in the database. // // "serial" is the certificate serial number // "password" is the one used to crypt privatekey and .p12 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 } else { return Certificate{serial, now, password, nil}, nil } } // Update applies modifications back to the database. func (c Certificate) Update() (int64, error) { if res, err := DBExec("UPDATE certificates SET creation = ?, password = ?, revoked = ? WHERE id_cert = ?", c.Creation, c.Password, c.Revoked, c.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err } else { return nb, err } } // Revoke the certificate in database. func (c *Certificate) Revoke() (int64, error) { now := time.Now() c.Revoked = &now return c.Update() } // Delete the certificate entry in the database. func (c Certificate) Delete() (int64, error) { if res, err := DBExec("DELETE FROM certificates WHERE id_cert = ?", c.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err } else { return nb, err } } // ClearCertificates removes all certificates from database. func ClearCertificates() (int64, error) { if res, err := DBExec("DELETE FROM certificates"); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err } else { return nb, err } }