From ba1374a881906d3b70d895389cb50d609f75789d Mon Sep 17 00:00:00 2001 From: Kayra Date: Tue, 26 Mar 2024 16:50:36 +0300 Subject: [PATCH 01/16] skelly --- .gitignore | 1 + cmd/gocert/main.go | 14 +++++- go.mod | 2 + go.sum | 2 + internal/certdb/certdb.go | 76 ++++++++++++++++++++++++++++++ internal/certdb/certdb_test.go | 9 ++++ internal/certdb/validation.go | 13 +++++ internal/certdb/validation_test.go | 1 + 8 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 go.sum create mode 100644 internal/certdb/certdb.go create mode 100644 internal/certdb/certdb_test.go create mode 100644 internal/certdb/validation.go create mode 100644 internal/certdb/validation_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3997bea --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.db \ No newline at end of file diff --git a/cmd/gocert/main.go b/cmd/gocert/main.go index ed53fd7..c568424 100644 --- a/cmd/gocert/main.go +++ b/cmd/gocert/main.go @@ -1,5 +1,17 @@ package main +import ( + "log" + + "github.com/canonical/gocert/internal/certdb" +) + func main() { - // ... + db := new(certdb.CertificateRequests) + if err := db.Connect(); err != nil { + log.Fatal(err) + } + defer db.Disconnect() + + // Serve server } diff --git a/go.mod b/go.mod index 50e6ec0..25e0f9b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/canonical/gocert go 1.22.1 + +require github.com/mattn/go-sqlite3 v1.14.22 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e8d092a --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go new file mode 100644 index 0000000..7634433 --- /dev/null +++ b/internal/certdb/certdb.go @@ -0,0 +1,76 @@ +package certdb + +import ( + "database/sql" + + _ "github.com/mattn/go-sqlite3" +) + +const queryCreateTable = `CREATE TABLE IF NOT EXISTS CertificateRequests ( + id INT PRIMARY KEY UNIQUE, + CSR VARCHAR UNIQUE NOT NULL, + Certificate VARCHAR DEFAULT "" + )` + +type CertificateRequests struct { + conn *sql.DB + data []CertificateRequest +} + +type CertificateRequest struct { + ID int + CSR string + Certificate string +} + +func (c *CertificateRequests) Create() error { + return nil +} + +func (c *CertificateRequests) Retrieve() (*CertificateRequest, error) { + return nil, sql.ErrNoRows +} + +func (c *CertificateRequests) Update() error { + + return nil +} + +func (c *CertificateRequests) Delete() error { + + return nil +} + +func (t *CertificateRequests) Connect() error { + // Connect to local DB + conn, err := sql.Open("sqlite3", "./certs.db") + if err != nil { + return err + } + t.conn = conn + if err := t.conn.Ping(); err != nil { + return err + } + if _, err := t.conn.Exec(queryCreateTable); err != nil { + return err + } + rows, err := t.conn.Query("SELECT * FROM CertificateRequests") + if err != nil { + return err + } + + defer rows.Close() + for rows.Next() { + var csr CertificateRequest + if err := rows.Scan(&csr.ID, &csr.CSR, &csr.Certificate); err != nil { + return err + } + t.data = append(t.data, csr) + } + + return nil +} + +func (t *CertificateRequests) Disconnect() { + // Disconnect from database and table +} diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go new file mode 100644 index 0000000..6c5dfb8 --- /dev/null +++ b/internal/certdb/certdb_test.go @@ -0,0 +1,9 @@ +package certdb + +import ( + "testing" +) + +func TestConnect(t *testing.T) { + +} diff --git a/internal/certdb/validation.go b/internal/certdb/validation.go new file mode 100644 index 0000000..d9e5029 --- /dev/null +++ b/internal/certdb/validation.go @@ -0,0 +1,13 @@ +package certdb + +func ValidateCertificateRequest(csr string) error { + return nil +} + +func ValidateCertificate(cert string, csr string) error { + + if csr == "" { + return nil + } + return nil +} diff --git a/internal/certdb/validation_test.go b/internal/certdb/validation_test.go new file mode 100644 index 0000000..18158c9 --- /dev/null +++ b/internal/certdb/validation_test.go @@ -0,0 +1 @@ +package certdb From 37078a64b7d8ae46fc60e8720c571d39277f4ee3 Mon Sep 17 00:00:00 2001 From: Kayra Date: Wed, 27 Mar 2024 13:17:21 +0300 Subject: [PATCH 02/16] feature complete --- cmd/gocert/main.go | 12 ++-- internal/certdb/certdb.go | 117 +++++++++++++++++++++++----------- internal/certdb/validation.go | 8 +-- 3 files changed, 88 insertions(+), 49 deletions(-) diff --git a/cmd/gocert/main.go b/cmd/gocert/main.go index c568424..935f2a2 100644 --- a/cmd/gocert/main.go +++ b/cmd/gocert/main.go @@ -1,17 +1,19 @@ package main import ( - "log" + "fmt" "github.com/canonical/gocert/internal/certdb" ) +var db *certdb.CertificateRequests + func main() { - db := new(certdb.CertificateRequests) - if err := db.Connect(); err != nil { - log.Fatal(err) + db = new(certdb.CertificateRequests) + if err := db.Connect("./certs.db", "CertificateRequests"); err != nil { + fmt.Println(err) } defer db.Disconnect() - // Serve server + // ListenAndServe } diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index 7634433..998de0c 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -6,71 +6,112 @@ import ( _ "github.com/mattn/go-sqlite3" ) -const queryCreateTable = `CREATE TABLE IF NOT EXISTS CertificateRequests ( - id INT PRIMARY KEY UNIQUE, - CSR VARCHAR UNIQUE NOT NULL, - Certificate VARCHAR DEFAULT "" +const queryCreateTable = `CREATE TABLE IF NOT EXISTS ? ( + CSR VARCHAR PRIMARY KEY UNIQUE NOT NULL, + Certificate VARCHAR )` +const queryGetAllCSRs = "SELECT rowid, * FROM ?" +const queryGetCSR = "SELECT rowid, * FROM ? WHERE CSR=?" +const queryCreateCSR = "INSERT INTO ? (CSR) VALUES (?)" +const queryUpdateCSR = "UPDATE ? SET Certificate=? WHERE CSR=?" +const queryDeleteCSR = "DELETE FROM ? WHERE CSR=?" + type CertificateRequests struct { - conn *sql.DB - data []CertificateRequest + table string + conn *sql.DB } type CertificateRequest struct { ID int CSR string - Certificate string + Certificate *string } -func (c *CertificateRequests) Create() error { - return nil -} +func (db *CertificateRequests) RetrieveAll() ([]*CertificateRequest, error) { + rows, err := db.conn.Query(queryGetAllCSRs, db.table) + if err != nil { + return nil, err + } -func (c *CertificateRequests) Retrieve() (*CertificateRequest, error) { - return nil, sql.ErrNoRows + var allCsrs []*CertificateRequest + defer rows.Close() + for rows.Next() { + var csr CertificateRequest + if err := rows.Scan(&csr.ID, &csr.CSR, &csr.Certificate); err != nil { + return nil, err + } + allCsrs = append(allCsrs, &csr) + } + return allCsrs, nil } -func (c *CertificateRequests) Update() error { - - return nil +func (db *CertificateRequests) Retrieve(csr *string) (*CertificateRequest, error) { + var newCSR CertificateRequest + row := db.conn.QueryRow(queryGetCSR, db.table, csr) + if err := row.Scan(&newCSR.ID, &newCSR.CSR, &newCSR.Certificate); err != nil { + return nil, err + } + return &newCSR, nil } -func (c *CertificateRequests) Delete() error { - - return nil +func (db *CertificateRequests) Create(csr *string) (int64, error) { + if err := ValidateCertificateRequest(csr); err != nil { + return 0, err + } + result, err := db.conn.Exec(queryCreateCSR, db.table, csr) + if err != nil { + return 0, err + } + id, err := result.LastInsertId() + if err != nil { + return 0, err + } + return id, nil } -func (t *CertificateRequests) Connect() error { - // Connect to local DB - conn, err := sql.Open("sqlite3", "./certs.db") +func (db *CertificateRequests) Update(csr *string, cert *string) (int64, error) { + if err := ValidateCertificate(cert, csr); err != nil { + return 0, err + } + result, err := db.conn.Exec(queryUpdateCSR, db.table, cert, csr) if err != nil { - return err + return 0, err } - t.conn = conn - if err := t.conn.Ping(); err != nil { - return err + id, err := result.LastInsertId() + if err != nil { + return 0, err } - if _, err := t.conn.Exec(queryCreateTable); err != nil { + return id, nil +} + +func (db *CertificateRequests) Delete(csr *string) error { + _, err := db.conn.Exec(queryDeleteCSR, db.table, csr) + if err != nil { return err } - rows, err := t.conn.Query("SELECT * FROM CertificateRequests") + return nil +} + +func (db *CertificateRequests) Connect(databasePath string, tableName string) error { + conn, err := sql.Open("sqlite3", databasePath) if err != nil { return err } - - defer rows.Close() - for rows.Next() { - var csr CertificateRequest - if err := rows.Scan(&csr.ID, &csr.CSR, &csr.Certificate); err != nil { - return err - } - t.data = append(t.data, csr) + db.table = tableName + db.conn = conn + if _, err := db.conn.Exec(queryCreateTable, db.table); err != nil { + return err } - return nil } -func (t *CertificateRequests) Disconnect() { - // Disconnect from database and table +func (db *CertificateRequests) Disconnect() error { + if db.conn == nil { + return nil + } + if err := db.conn.Close(); err != nil { + return err + } + return nil } diff --git a/internal/certdb/validation.go b/internal/certdb/validation.go index d9e5029..976ea72 100644 --- a/internal/certdb/validation.go +++ b/internal/certdb/validation.go @@ -1,13 +1,9 @@ package certdb -func ValidateCertificateRequest(csr string) error { +func ValidateCertificateRequest(csr *string) error { return nil } -func ValidateCertificate(cert string, csr string) error { - - if csr == "" { - return nil - } +func ValidateCertificate(cert *string, csr *string) error { return nil } From 2d60254d90568a5d4e53621ea79ed0f704e6fc73 Mon Sep 17 00:00:00 2001 From: Kayra Date: Thu, 28 Mar 2024 09:20:25 +0300 Subject: [PATCH 03/16] database tests done --- cmd/gocert/main.go | 2 +- internal/certdb/certdb.go | 28 ++++--- internal/certdb/certdb_test.go | 133 ++++++++++++++++++++++++++++++++- internal/certdb/validation.go | 40 +++++++++- 4 files changed, 184 insertions(+), 19 deletions(-) diff --git a/cmd/gocert/main.go b/cmd/gocert/main.go index 935f2a2..2677c13 100644 --- a/cmd/gocert/main.go +++ b/cmd/gocert/main.go @@ -10,7 +10,7 @@ var db *certdb.CertificateRequests func main() { db = new(certdb.CertificateRequests) - if err := db.Connect("./certs.db", "CertificateRequests"); err != nil { + if err := db.Connect("./certs.db", "CertificateReq"); err != nil { fmt.Println(err) } defer db.Disconnect() diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index 998de0c..48e7077 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -2,20 +2,18 @@ package certdb import ( "database/sql" + "fmt" _ "github.com/mattn/go-sqlite3" ) -const queryCreateTable = `CREATE TABLE IF NOT EXISTS ? ( - CSR VARCHAR PRIMARY KEY UNIQUE NOT NULL, - Certificate VARCHAR - )` +const queryCreateTable = "CREATE TABLE IF NOT EXISTS %s (CSR VARCHAR PRIMARY KEY UNIQUE NOT NULL, Certificate VARCHAR)" -const queryGetAllCSRs = "SELECT rowid, * FROM ?" -const queryGetCSR = "SELECT rowid, * FROM ? WHERE CSR=?" -const queryCreateCSR = "INSERT INTO ? (CSR) VALUES (?)" -const queryUpdateCSR = "UPDATE ? SET Certificate=? WHERE CSR=?" -const queryDeleteCSR = "DELETE FROM ? WHERE CSR=?" +const queryGetAllCSRs = "SELECT rowid, * FROM %s" +const queryGetCSR = "SELECT rowid, * FROM %s WHERE CSR=?" +const queryCreateCSR = "INSERT INTO %s (CSR) VALUES (?)" +const queryUpdateCSR = "UPDATE %s SET Certificate=? WHERE CSR=?" +const queryDeleteCSR = "DELETE FROM %s WHERE CSR=?" type CertificateRequests struct { table string @@ -29,7 +27,7 @@ type CertificateRequest struct { } func (db *CertificateRequests) RetrieveAll() ([]*CertificateRequest, error) { - rows, err := db.conn.Query(queryGetAllCSRs, db.table) + rows, err := db.conn.Query(fmt.Sprintf(queryGetAllCSRs, db.table)) if err != nil { return nil, err } @@ -48,7 +46,7 @@ func (db *CertificateRequests) RetrieveAll() ([]*CertificateRequest, error) { func (db *CertificateRequests) Retrieve(csr *string) (*CertificateRequest, error) { var newCSR CertificateRequest - row := db.conn.QueryRow(queryGetCSR, db.table, csr) + row := db.conn.QueryRow(fmt.Sprintf(queryGetCSR, db.table), csr) if err := row.Scan(&newCSR.ID, &newCSR.CSR, &newCSR.Certificate); err != nil { return nil, err } @@ -59,7 +57,7 @@ func (db *CertificateRequests) Create(csr *string) (int64, error) { if err := ValidateCertificateRequest(csr); err != nil { return 0, err } - result, err := db.conn.Exec(queryCreateCSR, db.table, csr) + result, err := db.conn.Exec(fmt.Sprintf(queryCreateCSR, db.table), csr) if err != nil { return 0, err } @@ -74,7 +72,7 @@ func (db *CertificateRequests) Update(csr *string, cert *string) (int64, error) if err := ValidateCertificate(cert, csr); err != nil { return 0, err } - result, err := db.conn.Exec(queryUpdateCSR, db.table, cert, csr) + result, err := db.conn.Exec(fmt.Sprintf(queryUpdateCSR, db.table), cert, csr) if err != nil { return 0, err } @@ -86,7 +84,7 @@ func (db *CertificateRequests) Update(csr *string, cert *string) (int64, error) } func (db *CertificateRequests) Delete(csr *string) error { - _, err := db.conn.Exec(queryDeleteCSR, db.table, csr) + _, err := db.conn.Exec(fmt.Sprintf(queryDeleteCSR, db.table), csr) if err != nil { return err } @@ -100,7 +98,7 @@ func (db *CertificateRequests) Connect(databasePath string, tableName string) er } db.table = tableName db.conn = conn - if _, err := db.conn.Exec(queryCreateTable, db.table); err != nil { + if _, err := db.conn.Exec(fmt.Sprintf(queryCreateTable, db.table)); err != nil { return err } return nil diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index 6c5dfb8..f4fc1ec 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -4,6 +4,137 @@ import ( "testing" ) -func TestConnect(t *testing.T) { +func TestConnection(t *testing.T) { + db := new(CertificateRequests) + defer db.Disconnect() + if err := db.Connect(":memory:", "CertificateReqs"); err != nil { + t.Fatalf("Can't connect to SQLite: %s", err) + } +} + +func TestDatabase(t *testing.T) { + db := new(CertificateRequests) + defer db.Disconnect() + db.Connect(":memory:", "CertificateRequests") + + csr1 := `-----BEGIN CERTIFICATE REQUEST----- +MIICszCCAZsCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDC5KgrADpuOUPwSh0YLmpWF66VTcciIGC2HcGn +oJknL7pm5q9qhfWGIdvKKlIA6cBB32jPd0QcYDsx7+AvzEvBuO7mq7v2Q1sPU4Q+ +L0s2pLJges6/cnDWvk/p5eBjDLOqHhUNzpMUga9SgIod8yymTZm3eqQvt1ABdwTg +FzBs5QdSm2Ny1fEbbcRE+Rv5rqXyJb2isXSujzSuS22VqslDIyqnY5WaLg+pjZyR ++0j13ecJsdh6/MJMUZWheimV2Yv7SFtxzFwbzBMO9YFS098sy4F896eBHLNe9cUC ++d1JDtLaewlMogjHBHAxmP54dhe6vvc78anElKKP4hm5N5nlAgMBAAGgWDBWBgkq +hkiG9w0BCQ4xSTBHMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEL +BQADggEBACP1VKEGVYKoVLMDJS+EZ0CPwIYWsO4xBXgK6atHe8WIChVn/8I7eo60 +cuMDiy4LR70G++xL1tpmYGRbx21r9d/shL2ehp9VdClX06qxlcGxiC/F8eThRuS5 +zHcdNqSVyMoLJ0c7yWHJahN5u2bn1Lov34yOEqGGpWCGF/gT1nEvM+p/v30s89f2 +Y/uPl4g3jpGqLCKTASWJDGnZLroLICOzYTVs5P3oj+VueSUwYhGK5tBnS2x5FHID +uMNMgwl0fxGMQZjrlXyCBhXBm1k6PmwcJGJF5LQ31c+5aTTMFU7SyZhlymctB8mS +y+ErBQsRpcQho6Ok+HTXQQUcx7WNcwI= +-----END CERTIFICATE REQUEST----- +` + csr2 := `-----BEGIN CERTIFICATE REQUEST----- +MIIC5zCCAc8CAQAwRzEWMBQGA1UEAwwNMTAuMTUyLjE4My41MzEtMCsGA1UELQwk +MzlhY2UxOTUtZGM1YS00MzJiLTgwOTAtYWZlNmFiNGI0OWNmMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjM5Wz+HRtDveRzeDkEDM4ornIaefe8d8nmFi +pUat9qCU3U9798FR460DHjCLGxFxxmoRitzHtaR4ew5H036HlGB20yas/CMDgSUI +69DyAsyPwEJqOWBGO1LL50qXdl5/jOkO2voA9j5UsD1CtWSklyhbNhWMpYqj2ObW +XcaYj9Gx/TwYhw8xsJ/QRWyCrvjjVzH8+4frfDhBVOyywN7sq+I3WwCbyBBcN8uO +yae0b/q5+UJUiqgpeOAh/4Y7qI3YarMj4cm7dwmiCVjedUwh65zVyHtQUfLd8nFW +Kl9775mNBc1yicvKDU3ZB5hZ1MZtpbMBwaA1yMSErs/fh5KaXwIDAQABoFswWQYJ +KoZIhvcNAQkOMUwwSjBIBgNVHREEQTA/hwQKmLc1gjd2YXVsdC1rOHMtMC52YXVs +dC1rOHMtZW5kcG9pbnRzLnZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsMA0GCSqGSIb3 +DQEBCwUAA4IBAQCJt8oVDbiuCsik4N5AOJIT7jKsMb+j0mizwjahKMoCHdx+zv0V +FGkhlf0VWPAdEu3gHdJfduX88WwzJ2wBBUK38UuprAyvfaZfaYUgFJQNC6DH1fIa +uHYEhvNJBdFJHaBvW7lrSFi57fTA9IEPrB3m/XN3r2F4eoHnaJJqHZmMwqVHck87 +cAQXk3fvTWuikHiCHqqdSdjDYj/8cyiwCrQWpV245VSbOE0WesWoEnSdFXVUfE1+ +RSKeTRuuJMcdGqBkDnDI22myj0bjt7q8eqBIjTiLQLnAFnQYpcCrhc8dKU9IJlv1 +H9Hay4ZO9LRew3pEtlx2WrExw/gpUcWM8rTI +-----END CERTIFICATE REQUEST-----` + + csr3 := `-----BEGIN CERTIFICATE REQUEST----- +MIICszCCAZsCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDN7tHggWTtxiT5Sh5Npoif8J2BdpJjtMdpZ7Vu +NVzMxW/eojSRlq0p3nafmpjnSdSH1k/XMmPsgmv9txxEHMw1LIUJUef2QVrQTI6J +4ueu9NvexZWXZ+UxFip63PKyn/CkZRFiHCRIGzDDPxM2aApjghXy9ISMtGqDVSnr +5hQDu2U1CEiUWKMoTpyk/KlBZliDDOzaGm3cQuzKWs6Stjzpq+uX4ecJAXZg5Cj+ ++JUETH93A/VOfsiiHXoKeTnFMCsmJgEHz2DZixw8EN8XgpOp5BA2n8Y/xS+Ren5R +ZH7uNJI/SmQ0yrR+2bYR6hm+4bCzspyCfzbiuI5IS9+2eXA/AgMBAAGgWDBWBgkq +hkiG9w0BCQ4xSTBHMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEL +BQADggEBAB/aPfYLbnCubYyKnxLRipoLr3TBSYFnRfcxiZR1o+L3/tuv2NlrXJjY +K13xzzPhwuZwd6iKfX3xC33sKgnUNFawyE8IuAmyhJ2cl97iA2lwoYcyuWP9TOEx +LT60zxp7PHsKo53gqaqRJ5B9RZtiv1jYdUZvynHP4J5JG7Zwaa0VNi/Cx5cwGW8K +rfvNABPUAU6xIqqYgd2heDPF6kjvpoNiOl056qIAbk0dbmpqOJf/lxKBRfqlHhSC +0qRScGu70l2Oxl89YSsfGtUyQuzTkLshI2VkEUM+W/ZauXbxLd8SyWveH3/7mDC+ +Sgi7T+lz+c1Tw+XFgkqryUwMeG2wxt8= +-----END CERTIFICATE REQUEST----- +` + + cert2 := `-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgIURKr+jf7hj60SyAryIeN++9wDdtkwDQYJKoZIhvcNAQEL +BQAwOTELMAkGA1UEBhMCVVMxKjAoBgNVBAMMIXNlbGYtc2lnbmVkLWNlcnRpZmlj +YXRlcy1vcGVyYXRvcjAeFw0yNDAzMjcxMjQ4MDRaFw0yNTAzMjcxMjQ4MDRaMEcx +FjAUBgNVBAMMDTEwLjE1Mi4xODMuNTMxLTArBgNVBC0MJDM5YWNlMTk1LWRjNWEt +NDMyYi04MDkwLWFmZTZhYjRiNDljZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAIzOVs/h0bQ73kc3g5BAzOKK5yGnn3vHfJ5hYqVGrfaglN1Pe/fBUeOt +Ax4wixsRccZqEYrcx7WkeHsOR9N+h5RgdtMmrPwjA4ElCOvQ8gLMj8BCajlgRjtS +y+dKl3Zef4zpDtr6APY+VLA9QrVkpJcoWzYVjKWKo9jm1l3GmI/Rsf08GIcPMbCf +0EVsgq7441cx/PuH63w4QVTsssDe7KviN1sAm8gQXDfLjsmntG/6uflCVIqoKXjg +If+GO6iN2GqzI+HJu3cJoglY3nVMIeuc1ch7UFHy3fJxVipfe++ZjQXNconLyg1N +2QeYWdTGbaWzAcGgNcjEhK7P34eSml8CAwEAAaOBnTCBmjAhBgNVHSMEGjAYgBYE +FN/vgl9cAapV7hH9lEyM7qYS958aMB0GA1UdDgQWBBRJJDZkHr64VqTC24DPQVld +Ba3iPDAMBgNVHRMBAf8EAjAAMEgGA1UdEQRBMD+CN3ZhdWx0LWs4cy0wLnZhdWx0 +LWs4cy1lbmRwb2ludHMudmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWyHBAqYtzUwDQYJ +KoZIhvcNAQELBQADggEBAEH9NTwDiSsoQt/QXkWPMBrB830K0dlwKl5WBNgVxFP+ +hSfQ86xN77jNSp2VxOksgzF9J9u/ubAXvSFsou4xdP8MevBXoFJXeqMERq5RW3gc +WyhXkzguv3dwH+n43GJFP6MQ+n9W/nPZCUQ0Iy7ueAvj0HFhGyZzAE2wxNFZdvCs +gCX3nqYpp70oZIFDrhmYwE5ij5KXlHD4/1IOfNUKCDmQDgGPLI1tVtwQLjeRq7Hg +XVelpl/LXTQawmJyvDaVT/Q9P+WqoDiMjrqF6Sy7DzNeeccWVqvqX5TVS6Ky56iS +Mvo/+PAJHkBciR5Xn+Wg2a+7vrZvT6CBoRSOTozlLSM= +-----END CERTIFICATE-----` + + if _, err := db.Create(&csr1); err != nil { + t.Fatalf("Couldn't complete Create: %s", err) + } + if _, err := db.Create(&csr2); err != nil { + t.Fatalf("Couldn't complete Create: %s", err) + } + if _, err := db.Create(&csr3); err != nil { + t.Fatalf("Couldn't complete Create: %s", err) + } + + res, err := db.RetrieveAll() + if err != nil { + t.Fatalf("Couldn't complete RetrieveAll: %s", err) + } + if len(res) != 3 { + t.Fatalf("One or more CSR's weren't found in DB") + } + retrievedCSR, err := db.Retrieve(&csr1) + if err != nil { + t.Fatalf("Couldn't complete Retrieve: %s", err) + } + if retrievedCSR.CSR != csr1 { + t.Fatalf("The CSR from the database doesn't match the CSR that was given") + } + + if err = db.Delete(&csr1); err != nil { + t.Fatalf("Couldn't complete Delete: %s", err) + } + res, _ = db.RetrieveAll() + if len(res) != 2 { + t.Fatalf("CSR's weren't deleted from the DB properly") + } + _, err = db.Update(&csr2, &cert2) + if err != nil { + t.Fatalf("Couldn't complete Update: %s", err) + } + retrievedCSR, _ = db.Retrieve(&csr2) + if *retrievedCSR.Certificate != cert2 { + t.Fatalf("The certificate that was uploaded does not match the certificate that was given: Retrieved: %s\nGiven: %s", *retrievedCSR.Certificate, cert2) + } } diff --git a/internal/certdb/validation.go b/internal/certdb/validation.go index 976ea72..c346d42 100644 --- a/internal/certdb/validation.go +++ b/internal/certdb/validation.go @@ -1,9 +1,45 @@ package certdb -func ValidateCertificateRequest(csr *string) error { +import ( + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" +) + +func ValidateCertificateRequest(csrString *string) error { + block, _ := pem.Decode([]byte(*csrString)) + if block == nil { + return errors.New("PEM Certificate Request string not found or malformed") + } + if block.Type != "CERTIFICATE REQUEST" { + return errors.New("given PEM string not a certificate request") + } + _, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return err + } return nil } -func ValidateCertificate(cert *string, csr *string) error { +func ValidateCertificate(certString *string, csrString *string) error { + if err := ValidateCertificateRequest(csrString); err != nil { + return err + } + csrBlock, _ := pem.Decode([]byte(*csrString)) + csr, _ := x509.ParseCertificateRequest(csrBlock.Bytes) + certBlock, _ := pem.Decode([]byte(*certString)) + if certBlock == nil { + return errors.New("PEM Certificate string not found or malformed") + } + cert, err := x509.ParseCertificate(certBlock.Bytes) + if err != nil { + return err + } + certKey := cert.PublicKey.(*rsa.PublicKey) + csrKey := csr.PublicKey.(*rsa.PublicKey) + if csrKey.Equal(*certKey) { + return errors.New("certificate does not match CSR") + } return nil } From c925d475c65aa7d4d4670e231bc2164997759d6e Mon Sep 17 00:00:00 2001 From: Kayra Date: Thu, 28 Mar 2024 11:22:44 +0300 Subject: [PATCH 04/16] tests done and passing --- internal/certdb/certdb_test.go | 107 +++---------------- internal/certdb/validation.go | 5 +- internal/certdb/validation_test.go | 161 ++++++++++++++++++++++++++++- 3 files changed, 179 insertions(+), 94 deletions(-) diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index f4fc1ec..0f2fad5 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -1,11 +1,13 @@ -package certdb +package certdb_test import ( "testing" + + "github.com/canonical/gocert/internal/certdb" ) func TestConnection(t *testing.T) { - db := new(CertificateRequests) + db := new(certdb.CertificateRequests) defer db.Disconnect() if err := db.Connect(":memory:", "CertificateReqs"); err != nil { t.Fatalf("Can't connect to SQLite: %s", err) @@ -13,96 +15,17 @@ func TestConnection(t *testing.T) { } func TestDatabase(t *testing.T) { - db := new(CertificateRequests) + db := new(certdb.CertificateRequests) defer db.Disconnect() db.Connect(":memory:", "CertificateRequests") - csr1 := `-----BEGIN CERTIFICATE REQUEST----- -MIICszCCAZsCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDC5KgrADpuOUPwSh0YLmpWF66VTcciIGC2HcGn -oJknL7pm5q9qhfWGIdvKKlIA6cBB32jPd0QcYDsx7+AvzEvBuO7mq7v2Q1sPU4Q+ -L0s2pLJges6/cnDWvk/p5eBjDLOqHhUNzpMUga9SgIod8yymTZm3eqQvt1ABdwTg -FzBs5QdSm2Ny1fEbbcRE+Rv5rqXyJb2isXSujzSuS22VqslDIyqnY5WaLg+pjZyR -+0j13ecJsdh6/MJMUZWheimV2Yv7SFtxzFwbzBMO9YFS098sy4F896eBHLNe9cUC -+d1JDtLaewlMogjHBHAxmP54dhe6vvc78anElKKP4hm5N5nlAgMBAAGgWDBWBgkq -hkiG9w0BCQ4xSTBHMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD -AQYIKwYBBQUHAwIwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEL -BQADggEBACP1VKEGVYKoVLMDJS+EZ0CPwIYWsO4xBXgK6atHe8WIChVn/8I7eo60 -cuMDiy4LR70G++xL1tpmYGRbx21r9d/shL2ehp9VdClX06qxlcGxiC/F8eThRuS5 -zHcdNqSVyMoLJ0c7yWHJahN5u2bn1Lov34yOEqGGpWCGF/gT1nEvM+p/v30s89f2 -Y/uPl4g3jpGqLCKTASWJDGnZLroLICOzYTVs5P3oj+VueSUwYhGK5tBnS2x5FHID -uMNMgwl0fxGMQZjrlXyCBhXBm1k6PmwcJGJF5LQ31c+5aTTMFU7SyZhlymctB8mS -y+ErBQsRpcQho6Ok+HTXQQUcx7WNcwI= ------END CERTIFICATE REQUEST----- -` - csr2 := `-----BEGIN CERTIFICATE REQUEST----- -MIIC5zCCAc8CAQAwRzEWMBQGA1UEAwwNMTAuMTUyLjE4My41MzEtMCsGA1UELQwk -MzlhY2UxOTUtZGM1YS00MzJiLTgwOTAtYWZlNmFiNGI0OWNmMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjM5Wz+HRtDveRzeDkEDM4ornIaefe8d8nmFi -pUat9qCU3U9798FR460DHjCLGxFxxmoRitzHtaR4ew5H036HlGB20yas/CMDgSUI -69DyAsyPwEJqOWBGO1LL50qXdl5/jOkO2voA9j5UsD1CtWSklyhbNhWMpYqj2ObW -XcaYj9Gx/TwYhw8xsJ/QRWyCrvjjVzH8+4frfDhBVOyywN7sq+I3WwCbyBBcN8uO -yae0b/q5+UJUiqgpeOAh/4Y7qI3YarMj4cm7dwmiCVjedUwh65zVyHtQUfLd8nFW -Kl9775mNBc1yicvKDU3ZB5hZ1MZtpbMBwaA1yMSErs/fh5KaXwIDAQABoFswWQYJ -KoZIhvcNAQkOMUwwSjBIBgNVHREEQTA/hwQKmLc1gjd2YXVsdC1rOHMtMC52YXVs -dC1rOHMtZW5kcG9pbnRzLnZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsMA0GCSqGSIb3 -DQEBCwUAA4IBAQCJt8oVDbiuCsik4N5AOJIT7jKsMb+j0mizwjahKMoCHdx+zv0V -FGkhlf0VWPAdEu3gHdJfduX88WwzJ2wBBUK38UuprAyvfaZfaYUgFJQNC6DH1fIa -uHYEhvNJBdFJHaBvW7lrSFi57fTA9IEPrB3m/XN3r2F4eoHnaJJqHZmMwqVHck87 -cAQXk3fvTWuikHiCHqqdSdjDYj/8cyiwCrQWpV245VSbOE0WesWoEnSdFXVUfE1+ -RSKeTRuuJMcdGqBkDnDI22myj0bjt7q8eqBIjTiLQLnAFnQYpcCrhc8dKU9IJlv1 -H9Hay4ZO9LRew3pEtlx2WrExw/gpUcWM8rTI ------END CERTIFICATE REQUEST-----` - - csr3 := `-----BEGIN CERTIFICATE REQUEST----- -MIICszCCAZsCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDN7tHggWTtxiT5Sh5Npoif8J2BdpJjtMdpZ7Vu -NVzMxW/eojSRlq0p3nafmpjnSdSH1k/XMmPsgmv9txxEHMw1LIUJUef2QVrQTI6J -4ueu9NvexZWXZ+UxFip63PKyn/CkZRFiHCRIGzDDPxM2aApjghXy9ISMtGqDVSnr -5hQDu2U1CEiUWKMoTpyk/KlBZliDDOzaGm3cQuzKWs6Stjzpq+uX4ecJAXZg5Cj+ -+JUETH93A/VOfsiiHXoKeTnFMCsmJgEHz2DZixw8EN8XgpOp5BA2n8Y/xS+Ren5R -ZH7uNJI/SmQ0yrR+2bYR6hm+4bCzspyCfzbiuI5IS9+2eXA/AgMBAAGgWDBWBgkq -hkiG9w0BCQ4xSTBHMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD -AQYIKwYBBQUHAwIwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEL -BQADggEBAB/aPfYLbnCubYyKnxLRipoLr3TBSYFnRfcxiZR1o+L3/tuv2NlrXJjY -K13xzzPhwuZwd6iKfX3xC33sKgnUNFawyE8IuAmyhJ2cl97iA2lwoYcyuWP9TOEx -LT60zxp7PHsKo53gqaqRJ5B9RZtiv1jYdUZvynHP4J5JG7Zwaa0VNi/Cx5cwGW8K -rfvNABPUAU6xIqqYgd2heDPF6kjvpoNiOl056qIAbk0dbmpqOJf/lxKBRfqlHhSC -0qRScGu70l2Oxl89YSsfGtUyQuzTkLshI2VkEUM+W/ZauXbxLd8SyWveH3/7mDC+ -Sgi7T+lz+c1Tw+XFgkqryUwMeG2wxt8= ------END CERTIFICATE REQUEST----- -` - - cert2 := `-----BEGIN CERTIFICATE----- -MIIDrDCCApSgAwIBAgIURKr+jf7hj60SyAryIeN++9wDdtkwDQYJKoZIhvcNAQEL -BQAwOTELMAkGA1UEBhMCVVMxKjAoBgNVBAMMIXNlbGYtc2lnbmVkLWNlcnRpZmlj -YXRlcy1vcGVyYXRvcjAeFw0yNDAzMjcxMjQ4MDRaFw0yNTAzMjcxMjQ4MDRaMEcx -FjAUBgNVBAMMDTEwLjE1Mi4xODMuNTMxLTArBgNVBC0MJDM5YWNlMTk1LWRjNWEt -NDMyYi04MDkwLWFmZTZhYjRiNDljZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAIzOVs/h0bQ73kc3g5BAzOKK5yGnn3vHfJ5hYqVGrfaglN1Pe/fBUeOt -Ax4wixsRccZqEYrcx7WkeHsOR9N+h5RgdtMmrPwjA4ElCOvQ8gLMj8BCajlgRjtS -y+dKl3Zef4zpDtr6APY+VLA9QrVkpJcoWzYVjKWKo9jm1l3GmI/Rsf08GIcPMbCf -0EVsgq7441cx/PuH63w4QVTsssDe7KviN1sAm8gQXDfLjsmntG/6uflCVIqoKXjg -If+GO6iN2GqzI+HJu3cJoglY3nVMIeuc1ch7UFHy3fJxVipfe++ZjQXNconLyg1N -2QeYWdTGbaWzAcGgNcjEhK7P34eSml8CAwEAAaOBnTCBmjAhBgNVHSMEGjAYgBYE -FN/vgl9cAapV7hH9lEyM7qYS958aMB0GA1UdDgQWBBRJJDZkHr64VqTC24DPQVld -Ba3iPDAMBgNVHRMBAf8EAjAAMEgGA1UdEQRBMD+CN3ZhdWx0LWs4cy0wLnZhdWx0 -LWs4cy1lbmRwb2ludHMudmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWyHBAqYtzUwDQYJ -KoZIhvcNAQELBQADggEBAEH9NTwDiSsoQt/QXkWPMBrB830K0dlwKl5WBNgVxFP+ -hSfQ86xN77jNSp2VxOksgzF9J9u/ubAXvSFsou4xdP8MevBXoFJXeqMERq5RW3gc -WyhXkzguv3dwH+n43GJFP6MQ+n9W/nPZCUQ0Iy7ueAvj0HFhGyZzAE2wxNFZdvCs -gCX3nqYpp70oZIFDrhmYwE5ij5KXlHD4/1IOfNUKCDmQDgGPLI1tVtwQLjeRq7Hg -XVelpl/LXTQawmJyvDaVT/Q9P+WqoDiMjrqF6Sy7DzNeeccWVqvqX5TVS6Ky56iS -Mvo/+PAJHkBciR5Xn+Wg2a+7vrZvT6CBoRSOTozlLSM= ------END CERTIFICATE-----` - - if _, err := db.Create(&csr1); err != nil { + if _, err := db.Create(&ValidCSR1); err != nil { t.Fatalf("Couldn't complete Create: %s", err) } - if _, err := db.Create(&csr2); err != nil { + if _, err := db.Create(&ValidCSR2); err != nil { t.Fatalf("Couldn't complete Create: %s", err) } - if _, err := db.Create(&csr3); err != nil { + if _, err := db.Create(&ValidCSR3); err != nil { t.Fatalf("Couldn't complete Create: %s", err) } @@ -113,15 +36,15 @@ Mvo/+PAJHkBciR5Xn+Wg2a+7vrZvT6CBoRSOTozlLSM= if len(res) != 3 { t.Fatalf("One or more CSR's weren't found in DB") } - retrievedCSR, err := db.Retrieve(&csr1) + retrievedCSR, err := db.Retrieve(&ValidCSR1) if err != nil { t.Fatalf("Couldn't complete Retrieve: %s", err) } - if retrievedCSR.CSR != csr1 { + if retrievedCSR.CSR != ValidCSR1 { t.Fatalf("The CSR from the database doesn't match the CSR that was given") } - if err = db.Delete(&csr1); err != nil { + if err = db.Delete(&ValidCSR1); err != nil { t.Fatalf("Couldn't complete Delete: %s", err) } res, _ = db.RetrieveAll() @@ -129,12 +52,12 @@ Mvo/+PAJHkBciR5Xn+Wg2a+7vrZvT6CBoRSOTozlLSM= t.Fatalf("CSR's weren't deleted from the DB properly") } - _, err = db.Update(&csr2, &cert2) + _, err = db.Update(&ValidCSR2, &ValidCert2) if err != nil { t.Fatalf("Couldn't complete Update: %s", err) } - retrievedCSR, _ = db.Retrieve(&csr2) - if *retrievedCSR.Certificate != cert2 { - t.Fatalf("The certificate that was uploaded does not match the certificate that was given: Retrieved: %s\nGiven: %s", *retrievedCSR.Certificate, cert2) + retrievedCSR, _ = db.Retrieve(&ValidCSR2) + if *retrievedCSR.Certificate != ValidCert2 { + t.Fatalf("The certificate that was uploaded does not match the certificate that was given: Retrieved: %s\nGiven: %s", *retrievedCSR.Certificate, ValidCert2) } } diff --git a/internal/certdb/validation.go b/internal/certdb/validation.go index c346d42..1ad662f 100644 --- a/internal/certdb/validation.go +++ b/internal/certdb/validation.go @@ -32,13 +32,16 @@ func ValidateCertificate(certString *string, csrString *string) error { if certBlock == nil { return errors.New("PEM Certificate string not found or malformed") } + if certBlock.Type != "CERTIFICATE" { + return errors.New("given PEM string not a certificate") + } cert, err := x509.ParseCertificate(certBlock.Bytes) if err != nil { return err } certKey := cert.PublicKey.(*rsa.PublicKey) csrKey := csr.PublicKey.(*rsa.PublicKey) - if csrKey.Equal(*certKey) { + if !csrKey.Equal(certKey) { return errors.New("certificate does not match CSR") } return nil diff --git a/internal/certdb/validation_test.go b/internal/certdb/validation_test.go index 18158c9..31dc100 100644 --- a/internal/certdb/validation_test.go +++ b/internal/certdb/validation_test.go @@ -1 +1,160 @@ -package certdb +package certdb_test + +import ( + "strings" + "testing" + + "github.com/canonical/gocert/internal/certdb" +) + +var ValidCSR1 string = `-----BEGIN CERTIFICATE REQUEST----- +MIICszCCAZsCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDC5KgrADpuOUPwSh0YLmpWF66VTcciIGC2HcGn +oJknL7pm5q9qhfWGIdvKKlIA6cBB32jPd0QcYDsx7+AvzEvBuO7mq7v2Q1sPU4Q+ +L0s2pLJges6/cnDWvk/p5eBjDLOqHhUNzpMUga9SgIod8yymTZm3eqQvt1ABdwTg +FzBs5QdSm2Ny1fEbbcRE+Rv5rqXyJb2isXSujzSuS22VqslDIyqnY5WaLg+pjZyR ++0j13ecJsdh6/MJMUZWheimV2Yv7SFtxzFwbzBMO9YFS098sy4F896eBHLNe9cUC ++d1JDtLaewlMogjHBHAxmP54dhe6vvc78anElKKP4hm5N5nlAgMBAAGgWDBWBgkq +hkiG9w0BCQ4xSTBHMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEL +BQADggEBACP1VKEGVYKoVLMDJS+EZ0CPwIYWsO4xBXgK6atHe8WIChVn/8I7eo60 +cuMDiy4LR70G++xL1tpmYGRbx21r9d/shL2ehp9VdClX06qxlcGxiC/F8eThRuS5 +zHcdNqSVyMoLJ0c7yWHJahN5u2bn1Lov34yOEqGGpWCGF/gT1nEvM+p/v30s89f2 +Y/uPl4g3jpGqLCKTASWJDGnZLroLICOzYTVs5P3oj+VueSUwYhGK5tBnS2x5FHID +uMNMgwl0fxGMQZjrlXyCBhXBm1k6PmwcJGJF5LQ31c+5aTTMFU7SyZhlymctB8mS +y+ErBQsRpcQho6Ok+HTXQQUcx7WNcwI= +-----END CERTIFICATE REQUEST----- +` +var ValidCSR2 string = `-----BEGIN CERTIFICATE REQUEST----- +MIIC5zCCAc8CAQAwRzEWMBQGA1UEAwwNMTAuMTUyLjE4My41MzEtMCsGA1UELQwk +MzlhY2UxOTUtZGM1YS00MzJiLTgwOTAtYWZlNmFiNGI0OWNmMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjM5Wz+HRtDveRzeDkEDM4ornIaefe8d8nmFi +pUat9qCU3U9798FR460DHjCLGxFxxmoRitzHtaR4ew5H036HlGB20yas/CMDgSUI +69DyAsyPwEJqOWBGO1LL50qXdl5/jOkO2voA9j5UsD1CtWSklyhbNhWMpYqj2ObW +XcaYj9Gx/TwYhw8xsJ/QRWyCrvjjVzH8+4frfDhBVOyywN7sq+I3WwCbyBBcN8uO +yae0b/q5+UJUiqgpeOAh/4Y7qI3YarMj4cm7dwmiCVjedUwh65zVyHtQUfLd8nFW +Kl9775mNBc1yicvKDU3ZB5hZ1MZtpbMBwaA1yMSErs/fh5KaXwIDAQABoFswWQYJ +KoZIhvcNAQkOMUwwSjBIBgNVHREEQTA/hwQKmLc1gjd2YXVsdC1rOHMtMC52YXVs +dC1rOHMtZW5kcG9pbnRzLnZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsMA0GCSqGSIb3 +DQEBCwUAA4IBAQCJt8oVDbiuCsik4N5AOJIT7jKsMb+j0mizwjahKMoCHdx+zv0V +FGkhlf0VWPAdEu3gHdJfduX88WwzJ2wBBUK38UuprAyvfaZfaYUgFJQNC6DH1fIa +uHYEhvNJBdFJHaBvW7lrSFi57fTA9IEPrB3m/XN3r2F4eoHnaJJqHZmMwqVHck87 +cAQXk3fvTWuikHiCHqqdSdjDYj/8cyiwCrQWpV245VSbOE0WesWoEnSdFXVUfE1+ +RSKeTRuuJMcdGqBkDnDI22myj0bjt7q8eqBIjTiLQLnAFnQYpcCrhc8dKU9IJlv1 +H9Hay4ZO9LRew3pEtlx2WrExw/gpUcWM8rTI +-----END CERTIFICATE REQUEST-----` + +var ValidCSR3 string = `-----BEGIN CERTIFICATE REQUEST----- +MIICszCCAZsCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDN7tHggWTtxiT5Sh5Npoif8J2BdpJjtMdpZ7Vu +NVzMxW/eojSRlq0p3nafmpjnSdSH1k/XMmPsgmv9txxEHMw1LIUJUef2QVrQTI6J +4ueu9NvexZWXZ+UxFip63PKyn/CkZRFiHCRIGzDDPxM2aApjghXy9ISMtGqDVSnr +5hQDu2U1CEiUWKMoTpyk/KlBZliDDOzaGm3cQuzKWs6Stjzpq+uX4ecJAXZg5Cj+ ++JUETH93A/VOfsiiHXoKeTnFMCsmJgEHz2DZixw8EN8XgpOp5BA2n8Y/xS+Ren5R +ZH7uNJI/SmQ0yrR+2bYR6hm+4bCzspyCfzbiuI5IS9+2eXA/AgMBAAGgWDBWBgkq +hkiG9w0BCQ4xSTBHMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEL +BQADggEBAB/aPfYLbnCubYyKnxLRipoLr3TBSYFnRfcxiZR1o+L3/tuv2NlrXJjY +K13xzzPhwuZwd6iKfX3xC33sKgnUNFawyE8IuAmyhJ2cl97iA2lwoYcyuWP9TOEx +LT60zxp7PHsKo53gqaqRJ5B9RZtiv1jYdUZvynHP4J5JG7Zwaa0VNi/Cx5cwGW8K +rfvNABPUAU6xIqqYgd2heDPF6kjvpoNiOl056qIAbk0dbmpqOJf/lxKBRfqlHhSC +0qRScGu70l2Oxl89YSsfGtUyQuzTkLshI2VkEUM+W/ZauXbxLd8SyWveH3/7mDC+ +Sgi7T+lz+c1Tw+XFgkqryUwMeG2wxt8= +-----END CERTIFICATE REQUEST----- +` + +var ValidCert2 string = `-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgIURKr+jf7hj60SyAryIeN++9wDdtkwDQYJKoZIhvcNAQEL +BQAwOTELMAkGA1UEBhMCVVMxKjAoBgNVBAMMIXNlbGYtc2lnbmVkLWNlcnRpZmlj +YXRlcy1vcGVyYXRvcjAeFw0yNDAzMjcxMjQ4MDRaFw0yNTAzMjcxMjQ4MDRaMEcx +FjAUBgNVBAMMDTEwLjE1Mi4xODMuNTMxLTArBgNVBC0MJDM5YWNlMTk1LWRjNWEt +NDMyYi04MDkwLWFmZTZhYjRiNDljZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAIzOVs/h0bQ73kc3g5BAzOKK5yGnn3vHfJ5hYqVGrfaglN1Pe/fBUeOt +Ax4wixsRccZqEYrcx7WkeHsOR9N+h5RgdtMmrPwjA4ElCOvQ8gLMj8BCajlgRjtS +y+dKl3Zef4zpDtr6APY+VLA9QrVkpJcoWzYVjKWKo9jm1l3GmI/Rsf08GIcPMbCf +0EVsgq7441cx/PuH63w4QVTsssDe7KviN1sAm8gQXDfLjsmntG/6uflCVIqoKXjg +If+GO6iN2GqzI+HJu3cJoglY3nVMIeuc1ch7UFHy3fJxVipfe++ZjQXNconLyg1N +2QeYWdTGbaWzAcGgNcjEhK7P34eSml8CAwEAAaOBnTCBmjAhBgNVHSMEGjAYgBYE +FN/vgl9cAapV7hH9lEyM7qYS958aMB0GA1UdDgQWBBRJJDZkHr64VqTC24DPQVld +Ba3iPDAMBgNVHRMBAf8EAjAAMEgGA1UdEQRBMD+CN3ZhdWx0LWs4cy0wLnZhdWx0 +LWs4cy1lbmRwb2ludHMudmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWyHBAqYtzUwDQYJ +KoZIhvcNAQELBQADggEBAEH9NTwDiSsoQt/QXkWPMBrB830K0dlwKl5WBNgVxFP+ +hSfQ86xN77jNSp2VxOksgzF9J9u/ubAXvSFsou4xdP8MevBXoFJXeqMERq5RW3gc +WyhXkzguv3dwH+n43GJFP6MQ+n9W/nPZCUQ0Iy7ueAvj0HFhGyZzAE2wxNFZdvCs +gCX3nqYpp70oZIFDrhmYwE5ij5KXlHD4/1IOfNUKCDmQDgGPLI1tVtwQLjeRq7Hg +XVelpl/LXTQawmJyvDaVT/Q9P+WqoDiMjrqF6Sy7DzNeeccWVqvqX5TVS6Ky56iS +Mvo/+PAJHkBciR5Xn+Wg2a+7vrZvT6CBoRSOTozlLSM= +-----END CERTIFICATE-----` + +func TestCSRValidationSuccess(t *testing.T) { + if err := certdb.ValidateCertificateRequest(&ValidCSR1); err != nil { + t.Fatalf("Couldn't verify valid CSR: %s", err) + } + if err := certdb.ValidateCertificateRequest(&ValidCSR2); err != nil { + t.Fatalf("Couldn't verify valid CSR: %s", err) + } + if err := certdb.ValidateCertificateRequest(&ValidCSR3); err != nil { + t.Fatalf("Couldn't verify valid CSR: %s", err) + } +} + +func TestCSRValidationFail(t *testing.T) { + var wrongString string = "this is a real csr!!!" + err := certdb.ValidateCertificateRequest(&wrongString) + if err.Error() != "PEM Certificate Request string not found or malformed" { + t.Fatalf("Expected error not found:\nReceived: %s", err) + } + var ValidCSRWithoutWhitespace = strings.ReplaceAll(ValidCSR1, "\n", "") + err = certdb.ValidateCertificateRequest(&ValidCSRWithoutWhitespace) + if err.Error() != "PEM Certificate Request string not found or malformed" { + t.Fatalf("Expected error not found:\nReceived: %s", err) + } + var wrongPemType string = strings.ReplaceAll(ValidCSR1, "CERTIFICATE REQUEST", "SOME RANDOM PEM TYPE") + err = certdb.ValidateCertificateRequest(&wrongPemType) + if err.Error() != "given PEM string not a certificate request" { + t.Fatalf("Expected error not found:\nReceived: %s", err) + } + var InvalidCSR = strings.ReplaceAll(ValidCSR1, "/", "p") + err = certdb.ValidateCertificateRequest(&InvalidCSR) + if err == nil { + t.Fatalf("Expected CSR to fail validation") + } +} + +// Fuzz test + +func TestCertValidationSuccess(t *testing.T) { + if err := certdb.ValidateCertificate(&ValidCert2, &ValidCSR2); err != nil { + t.Fatalf("Expected cert to be valid") + } +} + +func TestCertValidationFail(t *testing.T) { + var wrongString string = "this is a real cert!!!" + err := certdb.ValidateCertificate(&wrongString, &ValidCSR2) + if err.Error() != "PEM Certificate string not found or malformed" { + t.Fatalf("Expected error not found:\nReceived: %s", err) + } + var ValidCertWithoutWhitespace = strings.ReplaceAll(ValidCert2, "\n", "") + err = certdb.ValidateCertificate(&ValidCertWithoutWhitespace, &ValidCSR2) + if err.Error() != "PEM Certificate string not found or malformed" { + t.Fatalf("Expected error not found:\nReceived: %s", err) + } + var wrongPemType string = strings.ReplaceAll(ValidCert2, "CERTIFICATE", "SOME RANDOM PEM TYPE") + err = certdb.ValidateCertificate(&wrongPemType, &ValidCSR2) + if err.Error() != "given PEM string not a certificate" { + t.Fatalf("Expected error not found:\nReceived: %s", err) + } + var InvalidCert = strings.ReplaceAll(ValidCert2, "M", "i") + err = certdb.ValidateCertificate(&InvalidCert, &ValidCSR2) + if err == nil { + t.Fatalf("Expected cert to fail validation") + } + err = certdb.ValidateCertificate(&ValidCert2, &ValidCSR1) + if err == nil || err.Error() != "certificate does not match CSR" { + t.Fatalf("Expected cert to not match CSR") + } +} + +// Fuzz test +// Examples From 4b27d979e8143624efd5fdc2bc5dbc18b6cea24f Mon Sep 17 00:00:00 2001 From: Kayra Date: Thu, 28 Mar 2024 12:00:16 +0300 Subject: [PATCH 05/16] moar tests --- go.mod | 2 +- internal/certdb/certdb_test.go | 51 ++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 25e0f9b..103d8a4 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/canonical/gocert go 1.22.1 -require github.com/mattn/go-sqlite3 v1.14.22 // indirect +require github.com/mattn/go-sqlite3 v1.14.22 diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index 0f2fad5..8cdd503 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -1,12 +1,13 @@ package certdb_test import ( + "strings" "testing" "github.com/canonical/gocert/internal/certdb" ) -func TestConnection(t *testing.T) { +func TestConnect(t *testing.T) { db := new(certdb.CertificateRequests) defer db.Disconnect() if err := db.Connect(":memory:", "CertificateReqs"); err != nil { @@ -14,7 +15,7 @@ func TestConnection(t *testing.T) { } } -func TestDatabase(t *testing.T) { +func TestEndToEnd(t *testing.T) { db := new(certdb.CertificateRequests) defer db.Disconnect() db.Connect(":memory:", "CertificateRequests") @@ -34,7 +35,7 @@ func TestDatabase(t *testing.T) { t.Fatalf("Couldn't complete RetrieveAll: %s", err) } if len(res) != 3 { - t.Fatalf("One or more CSR's weren't found in DB") + t.Fatalf("One or more CSRs weren't found in DB") } retrievedCSR, err := db.Retrieve(&ValidCSR1) if err != nil { @@ -61,3 +62,47 @@ func TestDatabase(t *testing.T) { t.Fatalf("The certificate that was uploaded does not match the certificate that was given: Retrieved: %s\nGiven: %s", *retrievedCSR.Certificate, ValidCert2) } } + +func TestCreateFails(t *testing.T) { + db := new(certdb.CertificateRequests) + db.Connect(":memory:", "CertificateReqs") + defer db.Disconnect() + + InvalidCSR := strings.ReplaceAll(ValidCSR1, "/", "+") + if _, err := db.Create(&InvalidCSR); err == nil { + t.Fatalf("Expected error due to invalid CSR") + } + + db.Create(&ValidCSR1) + if _, err := db.Create(&ValidCSR1); err == nil { + t.Fatalf("Expected error due to duplicate CSR") + } +} + +func TestUpdateFails(t *testing.T) { + db := new(certdb.CertificateRequests) + defer db.Disconnect() + db.Connect(":memory:", "CertificateRequests") + + db.Create(&ValidCSR1) + db.Create(&ValidCSR2) + InvalidCert := strings.ReplaceAll(ValidCert2, "/", "+") + if _, err := db.Update(&ValidCSR2, &InvalidCert); err == nil { + t.Fatalf("Expected updating with invalid cert to fail") + } + if _, err := db.Update(&ValidCSR1, &ValidCert2); err == nil { + t.Fatalf("Expected updating with mismatched cert to fail") + } +} + +func TestRetrieve(t *testing.T) { + db := new(certdb.CertificateRequests) + defer db.Disconnect() + db.Connect(":memory:", "CertificateRequests") + + db.Create(&ValidCSR1) + if _, err := db.Retrieve(&ValidCSR2); err == nil { + t.Fatalf("Expected failure looking for nonexistent CSR") + } + +} From 4791ad3759de365af5f3fe2bfbfe4f43759e6a30 Mon Sep 17 00:00:00 2001 From: Kayra Date: Thu, 28 Mar 2024 12:05:48 +0300 Subject: [PATCH 06/16] moved example to example func in tests --- cmd/gocert/main.go | 14 -------------- internal/certdb/certdb_test.go | 9 +++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/cmd/gocert/main.go b/cmd/gocert/main.go index 2677c13..42d1148 100644 --- a/cmd/gocert/main.go +++ b/cmd/gocert/main.go @@ -1,19 +1,5 @@ package main -import ( - "fmt" - - "github.com/canonical/gocert/internal/certdb" -) - -var db *certdb.CertificateRequests - func main() { - db = new(certdb.CertificateRequests) - if err := db.Connect("./certs.db", "CertificateReq"); err != nil { - fmt.Println(err) - } - defer db.Disconnect() - // ListenAndServe } diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index 8cdd503..57b6de0 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -1,6 +1,7 @@ package certdb_test import ( + "log" "strings" "testing" @@ -106,3 +107,11 @@ func TestRetrieve(t *testing.T) { } } + +func ExampleConnection() { + db := new(certdb.CertificateRequests) + if err := db.Connect("./certs.db", "CertificateReq"); err != nil { + log.Fatalln(err) + } + defer db.Disconnect() +} From 700a1f4f11a068c218f03c69311c16a2563e42d2 Mon Sep 17 00:00:00 2001 From: Kayra Date: Thu, 28 Mar 2024 12:09:13 +0300 Subject: [PATCH 07/16] named example properly --- internal/certdb/certdb_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index 57b6de0..5f6f909 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -108,7 +108,7 @@ func TestRetrieve(t *testing.T) { } -func ExampleConnection() { +func Example() { db := new(certdb.CertificateRequests) if err := db.Connect("./certs.db", "CertificateReq"); err != nil { log.Fatalln(err) From de22f277dae98e6288b5dbe8f8087b052f22e4a6 Mon Sep 17 00:00:00 2001 From: Kayra Date: Thu, 28 Mar 2024 18:06:10 +0300 Subject: [PATCH 08/16] removed pointers all around --- internal/certdb/certdb.go | 14 ++++++------- internal/certdb/certdb_test.go | 32 +++++++++++++++--------------- internal/certdb/validation.go | 10 +++++----- internal/certdb/validation_test.go | 26 ++++++++++++------------ 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index 48e7077..17e68cb 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -26,25 +26,25 @@ type CertificateRequest struct { Certificate *string } -func (db *CertificateRequests) RetrieveAll() ([]*CertificateRequest, error) { +func (db *CertificateRequests) RetrieveAll() ([]CertificateRequest, error) { rows, err := db.conn.Query(fmt.Sprintf(queryGetAllCSRs, db.table)) if err != nil { return nil, err } - var allCsrs []*CertificateRequest + var allCsrs []CertificateRequest defer rows.Close() for rows.Next() { var csr CertificateRequest if err := rows.Scan(&csr.ID, &csr.CSR, &csr.Certificate); err != nil { return nil, err } - allCsrs = append(allCsrs, &csr) + allCsrs = append(allCsrs, csr) } return allCsrs, nil } -func (db *CertificateRequests) Retrieve(csr *string) (*CertificateRequest, error) { +func (db *CertificateRequests) Retrieve(csr string) (*CertificateRequest, error) { var newCSR CertificateRequest row := db.conn.QueryRow(fmt.Sprintf(queryGetCSR, db.table), csr) if err := row.Scan(&newCSR.ID, &newCSR.CSR, &newCSR.Certificate); err != nil { @@ -53,7 +53,7 @@ func (db *CertificateRequests) Retrieve(csr *string) (*CertificateRequest, error return &newCSR, nil } -func (db *CertificateRequests) Create(csr *string) (int64, error) { +func (db *CertificateRequests) Create(csr string) (int64, error) { if err := ValidateCertificateRequest(csr); err != nil { return 0, err } @@ -68,7 +68,7 @@ func (db *CertificateRequests) Create(csr *string) (int64, error) { return id, nil } -func (db *CertificateRequests) Update(csr *string, cert *string) (int64, error) { +func (db *CertificateRequests) Update(csr string, cert string) (int64, error) { if err := ValidateCertificate(cert, csr); err != nil { return 0, err } @@ -83,7 +83,7 @@ func (db *CertificateRequests) Update(csr *string, cert *string) (int64, error) return id, nil } -func (db *CertificateRequests) Delete(csr *string) error { +func (db *CertificateRequests) Delete(csr string) error { _, err := db.conn.Exec(fmt.Sprintf(queryDeleteCSR, db.table), csr) if err != nil { return err diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index 5f6f909..b043581 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -21,13 +21,13 @@ func TestEndToEnd(t *testing.T) { defer db.Disconnect() db.Connect(":memory:", "CertificateRequests") - if _, err := db.Create(&ValidCSR1); err != nil { + if _, err := db.Create(ValidCSR1); err != nil { t.Fatalf("Couldn't complete Create: %s", err) } - if _, err := db.Create(&ValidCSR2); err != nil { + if _, err := db.Create(ValidCSR2); err != nil { t.Fatalf("Couldn't complete Create: %s", err) } - if _, err := db.Create(&ValidCSR3); err != nil { + if _, err := db.Create(ValidCSR3); err != nil { t.Fatalf("Couldn't complete Create: %s", err) } @@ -38,7 +38,7 @@ func TestEndToEnd(t *testing.T) { if len(res) != 3 { t.Fatalf("One or more CSRs weren't found in DB") } - retrievedCSR, err := db.Retrieve(&ValidCSR1) + retrievedCSR, err := db.Retrieve(ValidCSR1) if err != nil { t.Fatalf("Couldn't complete Retrieve: %s", err) } @@ -46,7 +46,7 @@ func TestEndToEnd(t *testing.T) { t.Fatalf("The CSR from the database doesn't match the CSR that was given") } - if err = db.Delete(&ValidCSR1); err != nil { + if err = db.Delete(ValidCSR1); err != nil { t.Fatalf("Couldn't complete Delete: %s", err) } res, _ = db.RetrieveAll() @@ -54,11 +54,11 @@ func TestEndToEnd(t *testing.T) { t.Fatalf("CSR's weren't deleted from the DB properly") } - _, err = db.Update(&ValidCSR2, &ValidCert2) + _, err = db.Update(ValidCSR2, ValidCert2) if err != nil { t.Fatalf("Couldn't complete Update: %s", err) } - retrievedCSR, _ = db.Retrieve(&ValidCSR2) + retrievedCSR, _ = db.Retrieve(ValidCSR2) if *retrievedCSR.Certificate != ValidCert2 { t.Fatalf("The certificate that was uploaded does not match the certificate that was given: Retrieved: %s\nGiven: %s", *retrievedCSR.Certificate, ValidCert2) } @@ -70,12 +70,12 @@ func TestCreateFails(t *testing.T) { defer db.Disconnect() InvalidCSR := strings.ReplaceAll(ValidCSR1, "/", "+") - if _, err := db.Create(&InvalidCSR); err == nil { + if _, err := db.Create(InvalidCSR); err == nil { t.Fatalf("Expected error due to invalid CSR") } - db.Create(&ValidCSR1) - if _, err := db.Create(&ValidCSR1); err == nil { + db.Create(ValidCSR1) + if _, err := db.Create(ValidCSR1); err == nil { t.Fatalf("Expected error due to duplicate CSR") } } @@ -85,13 +85,13 @@ func TestUpdateFails(t *testing.T) { defer db.Disconnect() db.Connect(":memory:", "CertificateRequests") - db.Create(&ValidCSR1) - db.Create(&ValidCSR2) + db.Create(ValidCSR1) + db.Create(ValidCSR2) InvalidCert := strings.ReplaceAll(ValidCert2, "/", "+") - if _, err := db.Update(&ValidCSR2, &InvalidCert); err == nil { + if _, err := db.Update(ValidCSR2, InvalidCert); err == nil { t.Fatalf("Expected updating with invalid cert to fail") } - if _, err := db.Update(&ValidCSR1, &ValidCert2); err == nil { + if _, err := db.Update(ValidCSR1, ValidCert2); err == nil { t.Fatalf("Expected updating with mismatched cert to fail") } } @@ -101,8 +101,8 @@ func TestRetrieve(t *testing.T) { defer db.Disconnect() db.Connect(":memory:", "CertificateRequests") - db.Create(&ValidCSR1) - if _, err := db.Retrieve(&ValidCSR2); err == nil { + db.Create(ValidCSR1) + if _, err := db.Retrieve(ValidCSR2); err == nil { t.Fatalf("Expected failure looking for nonexistent CSR") } diff --git a/internal/certdb/validation.go b/internal/certdb/validation.go index 1ad662f..cebd0a4 100644 --- a/internal/certdb/validation.go +++ b/internal/certdb/validation.go @@ -7,8 +7,8 @@ import ( "errors" ) -func ValidateCertificateRequest(csrString *string) error { - block, _ := pem.Decode([]byte(*csrString)) +func ValidateCertificateRequest(csrString string) error { + block, _ := pem.Decode([]byte(csrString)) if block == nil { return errors.New("PEM Certificate Request string not found or malformed") } @@ -22,13 +22,13 @@ func ValidateCertificateRequest(csrString *string) error { return nil } -func ValidateCertificate(certString *string, csrString *string) error { +func ValidateCertificate(certString string, csrString string) error { if err := ValidateCertificateRequest(csrString); err != nil { return err } - csrBlock, _ := pem.Decode([]byte(*csrString)) + csrBlock, _ := pem.Decode([]byte(csrString)) csr, _ := x509.ParseCertificateRequest(csrBlock.Bytes) - certBlock, _ := pem.Decode([]byte(*certString)) + certBlock, _ := pem.Decode([]byte(certString)) if certBlock == nil { return errors.New("PEM Certificate string not found or malformed") } diff --git a/internal/certdb/validation_test.go b/internal/certdb/validation_test.go index 31dc100..4e1f4ee 100644 --- a/internal/certdb/validation_test.go +++ b/internal/certdb/validation_test.go @@ -87,35 +87,35 @@ Mvo/+PAJHkBciR5Xn+Wg2a+7vrZvT6CBoRSOTozlLSM= -----END CERTIFICATE-----` func TestCSRValidationSuccess(t *testing.T) { - if err := certdb.ValidateCertificateRequest(&ValidCSR1); err != nil { + if err := certdb.ValidateCertificateRequest(ValidCSR1); err != nil { t.Fatalf("Couldn't verify valid CSR: %s", err) } - if err := certdb.ValidateCertificateRequest(&ValidCSR2); err != nil { + if err := certdb.ValidateCertificateRequest(ValidCSR2); err != nil { t.Fatalf("Couldn't verify valid CSR: %s", err) } - if err := certdb.ValidateCertificateRequest(&ValidCSR3); err != nil { + if err := certdb.ValidateCertificateRequest(ValidCSR3); err != nil { t.Fatalf("Couldn't verify valid CSR: %s", err) } } func TestCSRValidationFail(t *testing.T) { var wrongString string = "this is a real csr!!!" - err := certdb.ValidateCertificateRequest(&wrongString) + err := certdb.ValidateCertificateRequest(wrongString) if err.Error() != "PEM Certificate Request string not found or malformed" { t.Fatalf("Expected error not found:\nReceived: %s", err) } var ValidCSRWithoutWhitespace = strings.ReplaceAll(ValidCSR1, "\n", "") - err = certdb.ValidateCertificateRequest(&ValidCSRWithoutWhitespace) + err = certdb.ValidateCertificateRequest(ValidCSRWithoutWhitespace) if err.Error() != "PEM Certificate Request string not found or malformed" { t.Fatalf("Expected error not found:\nReceived: %s", err) } var wrongPemType string = strings.ReplaceAll(ValidCSR1, "CERTIFICATE REQUEST", "SOME RANDOM PEM TYPE") - err = certdb.ValidateCertificateRequest(&wrongPemType) + err = certdb.ValidateCertificateRequest(wrongPemType) if err.Error() != "given PEM string not a certificate request" { t.Fatalf("Expected error not found:\nReceived: %s", err) } var InvalidCSR = strings.ReplaceAll(ValidCSR1, "/", "p") - err = certdb.ValidateCertificateRequest(&InvalidCSR) + err = certdb.ValidateCertificateRequest(InvalidCSR) if err == nil { t.Fatalf("Expected CSR to fail validation") } @@ -124,33 +124,33 @@ func TestCSRValidationFail(t *testing.T) { // Fuzz test func TestCertValidationSuccess(t *testing.T) { - if err := certdb.ValidateCertificate(&ValidCert2, &ValidCSR2); err != nil { + if err := certdb.ValidateCertificate(ValidCert2, ValidCSR2); err != nil { t.Fatalf("Expected cert to be valid") } } func TestCertValidationFail(t *testing.T) { var wrongString string = "this is a real cert!!!" - err := certdb.ValidateCertificate(&wrongString, &ValidCSR2) + err := certdb.ValidateCertificate(wrongString, ValidCSR2) if err.Error() != "PEM Certificate string not found or malformed" { t.Fatalf("Expected error not found:\nReceived: %s", err) } var ValidCertWithoutWhitespace = strings.ReplaceAll(ValidCert2, "\n", "") - err = certdb.ValidateCertificate(&ValidCertWithoutWhitespace, &ValidCSR2) + err = certdb.ValidateCertificate(ValidCertWithoutWhitespace, ValidCSR2) if err.Error() != "PEM Certificate string not found or malformed" { t.Fatalf("Expected error not found:\nReceived: %s", err) } var wrongPemType string = strings.ReplaceAll(ValidCert2, "CERTIFICATE", "SOME RANDOM PEM TYPE") - err = certdb.ValidateCertificate(&wrongPemType, &ValidCSR2) + err = certdb.ValidateCertificate(wrongPemType, ValidCSR2) if err.Error() != "given PEM string not a certificate" { t.Fatalf("Expected error not found:\nReceived: %s", err) } var InvalidCert = strings.ReplaceAll(ValidCert2, "M", "i") - err = certdb.ValidateCertificate(&InvalidCert, &ValidCSR2) + err = certdb.ValidateCertificate(InvalidCert, ValidCSR2) if err == nil { t.Fatalf("Expected cert to fail validation") } - err = certdb.ValidateCertificate(&ValidCert2, &ValidCSR1) + err = certdb.ValidateCertificate(ValidCert2, ValidCSR1) if err == nil || err.Error() != "certificate does not match CSR" { t.Fatalf("Expected cert to not match CSR") } From efdfbfd090cff4497a24807ef4d172f33cab554d Mon Sep 17 00:00:00 2001 From: Kayra Date: Mon, 1 Apr 2024 13:37:17 +0300 Subject: [PATCH 09/16] comments --- internal/certdb/certdb.go | 20 ++++++++-------- internal/certdb/certdb_test.go | 44 +++++++++++++++++----------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index 17e68cb..f163e6a 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -7,7 +7,7 @@ import ( _ "github.com/mattn/go-sqlite3" ) -const queryCreateTable = "CREATE TABLE IF NOT EXISTS %s (CSR VARCHAR PRIMARY KEY UNIQUE NOT NULL, Certificate VARCHAR)" +const queryCreateTable = "CREATE TABLE IF NOT EXISTS %s (CSR VARCHAR PRIMARY KEY UNIQUE NOT NULL, Certificate VARCHAR DEFAULT '')" const queryGetAllCSRs = "SELECT rowid, * FROM %s" const queryGetCSR = "SELECT rowid, * FROM %s WHERE CSR=?" @@ -15,7 +15,7 @@ const queryCreateCSR = "INSERT INTO %s (CSR) VALUES (?)" const queryUpdateCSR = "UPDATE %s SET Certificate=? WHERE CSR=?" const queryDeleteCSR = "DELETE FROM %s WHERE CSR=?" -type CertificateRequests struct { +type CertificateRequestsRepository struct { table string conn *sql.DB } @@ -23,10 +23,10 @@ type CertificateRequests struct { type CertificateRequest struct { ID int CSR string - Certificate *string + Certificate string } -func (db *CertificateRequests) RetrieveAll() ([]CertificateRequest, error) { +func (db *CertificateRequestsRepository) RetrieveAll() ([]CertificateRequest, error) { rows, err := db.conn.Query(fmt.Sprintf(queryGetAllCSRs, db.table)) if err != nil { return nil, err @@ -44,7 +44,7 @@ func (db *CertificateRequests) RetrieveAll() ([]CertificateRequest, error) { return allCsrs, nil } -func (db *CertificateRequests) Retrieve(csr string) (*CertificateRequest, error) { +func (db *CertificateRequestsRepository) Retrieve(csr string) (*CertificateRequest, error) { var newCSR CertificateRequest row := db.conn.QueryRow(fmt.Sprintf(queryGetCSR, db.table), csr) if err := row.Scan(&newCSR.ID, &newCSR.CSR, &newCSR.Certificate); err != nil { @@ -53,7 +53,7 @@ func (db *CertificateRequests) Retrieve(csr string) (*CertificateRequest, error) return &newCSR, nil } -func (db *CertificateRequests) Create(csr string) (int64, error) { +func (db *CertificateRequestsRepository) Create(csr string) (int64, error) { if err := ValidateCertificateRequest(csr); err != nil { return 0, err } @@ -68,7 +68,7 @@ func (db *CertificateRequests) Create(csr string) (int64, error) { return id, nil } -func (db *CertificateRequests) Update(csr string, cert string) (int64, error) { +func (db *CertificateRequestsRepository) Update(csr string, cert string) (int64, error) { if err := ValidateCertificate(cert, csr); err != nil { return 0, err } @@ -83,7 +83,7 @@ func (db *CertificateRequests) Update(csr string, cert string) (int64, error) { return id, nil } -func (db *CertificateRequests) Delete(csr string) error { +func (db *CertificateRequestsRepository) Delete(csr string) error { _, err := db.conn.Exec(fmt.Sprintf(queryDeleteCSR, db.table), csr) if err != nil { return err @@ -91,7 +91,7 @@ func (db *CertificateRequests) Delete(csr string) error { return nil } -func (db *CertificateRequests) Connect(databasePath string, tableName string) error { +func (db *CertificateRequestsRepository) Connect(databasePath string, tableName string) error { conn, err := sql.Open("sqlite3", databasePath) if err != nil { return err @@ -104,7 +104,7 @@ func (db *CertificateRequests) Connect(databasePath string, tableName string) er return nil } -func (db *CertificateRequests) Disconnect() error { +func (db *CertificateRequestsRepository) Close() error { if db.conn == nil { return nil } diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index b043581..f937729 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -9,17 +9,17 @@ import ( ) func TestConnect(t *testing.T) { - db := new(certdb.CertificateRequests) - defer db.Disconnect() + db := new(certdb.CertificateRequestsRepository) + defer db.Close() if err := db.Connect(":memory:", "CertificateReqs"); err != nil { t.Fatalf("Can't connect to SQLite: %s", err) } } func TestEndToEnd(t *testing.T) { - db := new(certdb.CertificateRequests) - defer db.Disconnect() - db.Connect(":memory:", "CertificateRequests") + db := new(certdb.CertificateRequestsRepository) + defer db.Close() + db.Connect(":memory:", "CertificateRequests") //nolint:errcheck if _, err := db.Create(ValidCSR1); err != nil { t.Fatalf("Couldn't complete Create: %s", err) @@ -59,34 +59,34 @@ func TestEndToEnd(t *testing.T) { t.Fatalf("Couldn't complete Update: %s", err) } retrievedCSR, _ = db.Retrieve(ValidCSR2) - if *retrievedCSR.Certificate != ValidCert2 { - t.Fatalf("The certificate that was uploaded does not match the certificate that was given: Retrieved: %s\nGiven: %s", *retrievedCSR.Certificate, ValidCert2) + if retrievedCSR.Certificate != ValidCert2 { + t.Fatalf("The certificate that was uploaded does not match the certificate that was given: Retrieved: %s\nGiven: %s", retrievedCSR.Certificate, ValidCert2) } } func TestCreateFails(t *testing.T) { - db := new(certdb.CertificateRequests) - db.Connect(":memory:", "CertificateReqs") - defer db.Disconnect() + db := new(certdb.CertificateRequestsRepository) + db.Connect(":memory:", "CertificateReqs") //nolint:errcheck + defer db.Close() InvalidCSR := strings.ReplaceAll(ValidCSR1, "/", "+") if _, err := db.Create(InvalidCSR); err == nil { t.Fatalf("Expected error due to invalid CSR") } - db.Create(ValidCSR1) + db.Create(ValidCSR1) //nolint:errcheck if _, err := db.Create(ValidCSR1); err == nil { t.Fatalf("Expected error due to duplicate CSR") } } func TestUpdateFails(t *testing.T) { - db := new(certdb.CertificateRequests) - defer db.Disconnect() - db.Connect(":memory:", "CertificateRequests") + db := new(certdb.CertificateRequestsRepository) + defer db.Close() + db.Connect(":memory:", "CertificateRequests") //nolint:errcheck - db.Create(ValidCSR1) - db.Create(ValidCSR2) + db.Create(ValidCSR1) //nolint:errcheck + db.Create(ValidCSR2) //nolint:errcheck InvalidCert := strings.ReplaceAll(ValidCert2, "/", "+") if _, err := db.Update(ValidCSR2, InvalidCert); err == nil { t.Fatalf("Expected updating with invalid cert to fail") @@ -97,11 +97,11 @@ func TestUpdateFails(t *testing.T) { } func TestRetrieve(t *testing.T) { - db := new(certdb.CertificateRequests) - defer db.Disconnect() - db.Connect(":memory:", "CertificateRequests") + db := new(certdb.CertificateRequestsRepository) + defer db.Close() + db.Connect(":memory:", "CertificateRequests") //nolint:errcheck - db.Create(ValidCSR1) + db.Create(ValidCSR1) //nolint:errcheck if _, err := db.Retrieve(ValidCSR2); err == nil { t.Fatalf("Expected failure looking for nonexistent CSR") } @@ -109,9 +109,9 @@ func TestRetrieve(t *testing.T) { } func Example() { - db := new(certdb.CertificateRequests) + db := new(certdb.CertificateRequestsRepository) if err := db.Connect("./certs.db", "CertificateReq"); err != nil { log.Fatalln(err) } - defer db.Disconnect() + defer db.Close() } From 6b77d1bd29e739def7498cc949a7348c79348cb2 Mon Sep 17 00:00:00 2001 From: Kayra Date: Mon, 1 Apr 2024 13:55:13 +0300 Subject: [PATCH 10/16] changes --- internal/certdb/certdb.go | 29 +++++++++++++----------- internal/certdb/certdb_test.go | 40 +++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index f163e6a..4c831eb 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -1,3 +1,4 @@ +// Package certdb provides a simplistic ORM to communicate with an SQL database for storage package certdb import ( @@ -15,6 +16,7 @@ const queryCreateCSR = "INSERT INTO %s (CSR) VALUES (?)" const queryUpdateCSR = "UPDATE %s SET Certificate=? WHERE CSR=?" const queryDeleteCSR = "DELETE FROM %s WHERE CSR=?" +// CertificateRequestRepository is the object used to communicate with the established repository. type CertificateRequestsRepository struct { table string conn *sql.DB @@ -91,19 +93,6 @@ func (db *CertificateRequestsRepository) Delete(csr string) error { return nil } -func (db *CertificateRequestsRepository) Connect(databasePath string, tableName string) error { - conn, err := sql.Open("sqlite3", databasePath) - if err != nil { - return err - } - db.table = tableName - db.conn = conn - if _, err := db.conn.Exec(fmt.Sprintf(queryCreateTable, db.table)); err != nil { - return err - } - return nil -} - func (db *CertificateRequestsRepository) Close() error { if db.conn == nil { return nil @@ -113,3 +102,17 @@ func (db *CertificateRequestsRepository) Close() error { } return nil } + +func NewCertificateRequestsRepository(databasePath string, tableName string) (*CertificateRequestsRepository, error) { + conn, err := sql.Open("sqlite3", databasePath) + if err != nil { + return nil, err + } + if _, err := conn.Exec(fmt.Sprintf(queryCreateTable, tableName)); err != nil { + return nil, err + } + db := new(CertificateRequestsRepository) + db.conn = conn + db.table = tableName + return db, nil +} diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index f937729..9cbd903 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -9,17 +9,19 @@ import ( ) func TestConnect(t *testing.T) { - db := new(certdb.CertificateRequestsRepository) - defer db.Close() - if err := db.Connect(":memory:", "CertificateReqs"); err != nil { + db, err := certdb.NewCertificateRequestsRepository(":memory:", "CertificateReqs") + if err != nil { t.Fatalf("Can't connect to SQLite: %s", err) } + db.Close() } func TestEndToEnd(t *testing.T) { - db := new(certdb.CertificateRequestsRepository) + db, err := certdb.NewCertificateRequestsRepository(":memory:", "CertificateRequests") //nolint:errcheck + if err != nil { + t.Fatalf("Couldn't complete NewCertificateRequestsRepository: %s", err) + } defer db.Close() - db.Connect(":memory:", "CertificateRequests") //nolint:errcheck if _, err := db.Create(ValidCSR1); err != nil { t.Fatalf("Couldn't complete Create: %s", err) @@ -65,8 +67,7 @@ func TestEndToEnd(t *testing.T) { } func TestCreateFails(t *testing.T) { - db := new(certdb.CertificateRequestsRepository) - db.Connect(":memory:", "CertificateReqs") //nolint:errcheck + db, _ := certdb.NewCertificateRequestsRepository(":memory:", "CertificateReqs") //nolint:errcheck defer db.Close() InvalidCSR := strings.ReplaceAll(ValidCSR1, "/", "+") @@ -81,9 +82,8 @@ func TestCreateFails(t *testing.T) { } func TestUpdateFails(t *testing.T) { - db := new(certdb.CertificateRequestsRepository) + db, _ := certdb.NewCertificateRequestsRepository(":memory:", "CertificateRequests") //nolint:errcheck defer db.Close() - db.Connect(":memory:", "CertificateRequests") //nolint:errcheck db.Create(ValidCSR1) //nolint:errcheck db.Create(ValidCSR2) //nolint:errcheck @@ -97,9 +97,8 @@ func TestUpdateFails(t *testing.T) { } func TestRetrieve(t *testing.T) { - db := new(certdb.CertificateRequestsRepository) + db, _ := certdb.NewCertificateRequestsRepository(":memory:", "CertificateRequests") //nolint:errcheck defer db.Close() - db.Connect(":memory:", "CertificateRequests") //nolint:errcheck db.Create(ValidCSR1) //nolint:errcheck if _, err := db.Retrieve(ValidCSR2); err == nil { @@ -109,9 +108,24 @@ func TestRetrieve(t *testing.T) { } func Example() { - db := new(certdb.CertificateRequestsRepository) - if err := db.Connect("./certs.db", "CertificateReq"); err != nil { + db, err := certdb.NewCertificateRequestsRepository("./certs.db", "CertificateReq") + if err != nil { + log.Fatalln(err) + } + _, err = db.Create(ValidCSR2) + if err != nil { log.Fatalln(err) } + _, err = db.Update(ValidCSR2, ValidCert2) + if err != nil { + log.Fatalln(err) + } + entry, err := db.Retrieve(ValidCSR2) + if err != nil { + log.Fatalln(err) + } + if entry.Certificate != ValidCert2 { + log.Fatalln("Retrieved Certificate doesn't match Stored Certificate") + } defer db.Close() } From a9dabdaf0043edd864493bfa4292ca3623fac432 Mon Sep 17 00:00:00 2001 From: Kayra Date: Mon, 1 Apr 2024 14:10:44 +0300 Subject: [PATCH 11/16] add docstrings --- internal/certdb/certdb.go | 15 +++++++++++++++ internal/certdb/validation.go | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index 4c831eb..397baf6 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -22,12 +22,15 @@ type CertificateRequestsRepository struct { conn *sql.DB } +// A CertificateRequest struct represents an entry in the database. +// The object contains a Certificate Request, its matching Certificate if any, and the row ID. type CertificateRequest struct { ID int CSR string Certificate string } +// RetrieveAll gets every CertificateRequest entry in the table. func (db *CertificateRequestsRepository) RetrieveAll() ([]CertificateRequest, error) { rows, err := db.conn.Query(fmt.Sprintf(queryGetAllCSRs, db.table)) if err != nil { @@ -46,6 +49,8 @@ func (db *CertificateRequestsRepository) RetrieveAll() ([]CertificateRequest, er return allCsrs, nil } +// Retrieve gets a given CSR from the repository. +// It returns the row id and matching certificate alongside the CSR in a CertificateRequest object. func (db *CertificateRequestsRepository) Retrieve(csr string) (*CertificateRequest, error) { var newCSR CertificateRequest row := db.conn.QueryRow(fmt.Sprintf(queryGetCSR, db.table), csr) @@ -55,6 +60,8 @@ func (db *CertificateRequestsRepository) Retrieve(csr string) (*CertificateReque return &newCSR, nil } +// Create creates a new entry in the repository. +// The given CSR must be valid and unique func (db *CertificateRequestsRepository) Create(csr string) (int64, error) { if err := ValidateCertificateRequest(csr); err != nil { return 0, err @@ -70,6 +77,8 @@ func (db *CertificateRequestsRepository) Create(csr string) (int64, error) { return id, nil } +// Update adds a new cert to the given CSR in the repository. +// The given certificate must share the public key of the CSR and must be valid. func (db *CertificateRequestsRepository) Update(csr string, cert string) (int64, error) { if err := ValidateCertificate(cert, csr); err != nil { return 0, err @@ -85,6 +94,7 @@ func (db *CertificateRequestsRepository) Update(csr string, cert string) (int64, return id, nil } +// Delete removes a CSR from the database alongside the certificate that may have been generated for it. func (db *CertificateRequestsRepository) Delete(csr string) error { _, err := db.conn.Exec(fmt.Sprintf(queryDeleteCSR, db.table), csr) if err != nil { @@ -93,6 +103,7 @@ func (db *CertificateRequestsRepository) Delete(csr string) error { return nil } +// Close closes the connection to the repository cleanly. func (db *CertificateRequestsRepository) Close() error { if db.conn == nil { return nil @@ -103,6 +114,10 @@ func (db *CertificateRequestsRepository) Close() error { return nil } +// NewCertificateRequestsRepository connects to a given table in a given database, +// stores the connection information and returns an object containing the information. +// The database path must be a valid file path or ":memory:". +// The table will be created if it doesn't exist in the format expected by the package. func NewCertificateRequestsRepository(databasePath string, tableName string) (*CertificateRequestsRepository, error) { conn, err := sql.Open("sqlite3", databasePath) if err != nil { diff --git a/internal/certdb/validation.go b/internal/certdb/validation.go index cebd0a4..fb1c759 100644 --- a/internal/certdb/validation.go +++ b/internal/certdb/validation.go @@ -7,6 +7,9 @@ import ( "errors" ) +// ValidateCertificateRequest validates the given CSR string to the following: +// The string must be a valid PEM string, and should be of type CERTIFICATE REQUEST +// The PEM string should be able to be parsed into a x509 Certificate Request func ValidateCertificateRequest(csrString string) error { block, _ := pem.Decode([]byte(csrString)) if block == nil { @@ -22,6 +25,11 @@ func ValidateCertificateRequest(csrString string) error { return nil } +// ValidateCertificate validates the given Cert string to the following: +// The given CSR must pass the validation provided by ValidateCertificateRequest +// The cert string must be a valid PEM string, and should be of type CERTIFICATE +// The PEM string should be able to be parsed into a x509 Certificate +// The given cert and CSR must share the same public key func ValidateCertificate(certString string, csrString string) error { if err := ValidateCertificateRequest(csrString); err != nil { return err From 5a1b2be19ab907c6e680cc907037839aa92650b2 Mon Sep 17 00:00:00 2001 From: Kayra Date: Mon, 1 Apr 2024 14:52:13 +0300 Subject: [PATCH 12/16] move to subtests --- internal/certdb/certdb_test.go | 5 +- internal/certdb/validation_test.go | 151 +++++++++++++++++++---------- 2 files changed, 103 insertions(+), 53 deletions(-) diff --git a/internal/certdb/certdb_test.go b/internal/certdb/certdb_test.go index 9cbd903..4dfe946 100644 --- a/internal/certdb/certdb_test.go +++ b/internal/certdb/certdb_test.go @@ -127,5 +127,8 @@ func Example() { if entry.Certificate != ValidCert2 { log.Fatalln("Retrieved Certificate doesn't match Stored Certificate") } - defer db.Close() + err = db.Close() + if err != nil { + log.Fatalln(err) + } } diff --git a/internal/certdb/validation_test.go b/internal/certdb/validation_test.go index 4e1f4ee..02c54ce 100644 --- a/internal/certdb/validation_test.go +++ b/internal/certdb/validation_test.go @@ -1,6 +1,7 @@ package certdb_test import ( + "fmt" "strings" "testing" @@ -87,74 +88,120 @@ Mvo/+PAJHkBciR5Xn+Wg2a+7vrZvT6CBoRSOTozlLSM= -----END CERTIFICATE-----` func TestCSRValidationSuccess(t *testing.T) { - if err := certdb.ValidateCertificateRequest(ValidCSR1); err != nil { - t.Fatalf("Couldn't verify valid CSR: %s", err) - } - if err := certdb.ValidateCertificateRequest(ValidCSR2); err != nil { - t.Fatalf("Couldn't verify valid CSR: %s", err) - } - if err := certdb.ValidateCertificateRequest(ValidCSR3); err != nil { - t.Fatalf("Couldn't verify valid CSR: %s", err) + cases := []string{ValidCSR1, ValidCSR2, ValidCSR3} + + for i, c := range cases { + t.Run(fmt.Sprintf("ValidCSR%d", i), func(t *testing.T) { + if err := certdb.ValidateCertificateRequest(c); err != nil { + t.Fatalf("Couldn't verify valid CSR: %s", err) + } + }) } } func TestCSRValidationFail(t *testing.T) { - var wrongString string = "this is a real csr!!!" - err := certdb.ValidateCertificateRequest(wrongString) - if err.Error() != "PEM Certificate Request string not found or malformed" { - t.Fatalf("Expected error not found:\nReceived: %s", err) - } + var wrongString = "this is a real csr!!!" + var wrongStringErr = "PEM Certificate Request string not found or malformed" var ValidCSRWithoutWhitespace = strings.ReplaceAll(ValidCSR1, "\n", "") - err = certdb.ValidateCertificateRequest(ValidCSRWithoutWhitespace) - if err.Error() != "PEM Certificate Request string not found or malformed" { - t.Fatalf("Expected error not found:\nReceived: %s", err) - } - var wrongPemType string = strings.ReplaceAll(ValidCSR1, "CERTIFICATE REQUEST", "SOME RANDOM PEM TYPE") - err = certdb.ValidateCertificateRequest(wrongPemType) - if err.Error() != "given PEM string not a certificate request" { - t.Fatalf("Expected error not found:\nReceived: %s", err) - } + var ValidCSRWithoutWhitespaceErr = "PEM Certificate Request string not found or malformed" + var wrongPemType = strings.ReplaceAll(ValidCSR1, "CERTIFICATE REQUEST", "SOME RANDOM PEM TYPE") + var wrongPemTypeErr = "given PEM string not a certificate request" var InvalidCSR = strings.ReplaceAll(ValidCSR1, "/", "p") - err = certdb.ValidateCertificateRequest(InvalidCSR) - if err == nil { - t.Fatalf("Expected CSR to fail validation") + var InvalidCSRErr = "asn1: syntax error: invalid boolean" + + cases := []struct { + input string + expectedErr string + }{ + { + input: wrongString, + expectedErr: wrongStringErr, + }, + { + input: ValidCSRWithoutWhitespace, + expectedErr: ValidCSRWithoutWhitespaceErr, + }, + { + input: wrongPemType, + expectedErr: wrongPemTypeErr, + }, + { + input: InvalidCSR, + expectedErr: InvalidCSRErr, + }, } -} -// Fuzz test + for i, c := range cases { + t.Run(fmt.Sprintf("InvalidCSR%d", i), func(t *testing.T) { + err := certdb.ValidateCertificateRequest(c.input) + if err.Error() != c.expectedErr { + t.Fatalf("Expected error not found:\nReceived: %s\nExpected: %s", err, c.expectedErr) + } + }) + } +} func TestCertValidationSuccess(t *testing.T) { - if err := certdb.ValidateCertificate(ValidCert2, ValidCSR2); err != nil { - t.Fatalf("Expected cert to be valid") + cases := []string{ValidCert2} + + for i, c := range cases { + t.Run(fmt.Sprintf("ValidCert%d", i), func(t *testing.T) { + if err := certdb.ValidateCertificate(c, ValidCSR2); err != nil { + t.Fatalf("Couldn't verify valid Cert: %s", err) + } + }) } } func TestCertValidationFail(t *testing.T) { - var wrongString string = "this is a real cert!!!" - err := certdb.ValidateCertificate(wrongString, ValidCSR2) - if err.Error() != "PEM Certificate string not found or malformed" { - t.Fatalf("Expected error not found:\nReceived: %s", err) - } + var wrongCertString = "this is a real cert!!!" + var wrongCertStringErr = "PEM Certificate string not found or malformed" var ValidCertWithoutWhitespace = strings.ReplaceAll(ValidCert2, "\n", "") - err = certdb.ValidateCertificate(ValidCertWithoutWhitespace, ValidCSR2) - if err.Error() != "PEM Certificate string not found or malformed" { - t.Fatalf("Expected error not found:\nReceived: %s", err) - } - var wrongPemType string = strings.ReplaceAll(ValidCert2, "CERTIFICATE", "SOME RANDOM PEM TYPE") - err = certdb.ValidateCertificate(wrongPemType, ValidCSR2) - if err.Error() != "given PEM string not a certificate" { - t.Fatalf("Expected error not found:\nReceived: %s", err) - } + var ValidCertWithoutWhitespaceErr = "PEM Certificate string not found or malformed" + var wrongPemType = strings.ReplaceAll(ValidCert2, "CERTIFICATE", "SOME RANDOM PEM TYPE") + var wrongPemTypeErr = "given PEM string not a certificate" var InvalidCert = strings.ReplaceAll(ValidCert2, "M", "i") - err = certdb.ValidateCertificate(InvalidCert, ValidCSR2) - if err == nil { - t.Fatalf("Expected cert to fail validation") + var InvalidCertErr = "x509: malformed certificate" + var certificateDoesNotMatchErr = "certificate does not match CSR" + + cases := []struct { + inputCSR string + inputCert string + expectedErr string + }{ + { + inputCSR: ValidCSR2, + inputCert: wrongCertString, + expectedErr: wrongCertStringErr, + }, + { + inputCSR: ValidCSR2, + inputCert: ValidCertWithoutWhitespace, + expectedErr: ValidCertWithoutWhitespaceErr, + }, + { + inputCSR: ValidCSR2, + inputCert: wrongPemType, + expectedErr: wrongPemTypeErr, + }, + { + inputCSR: ValidCSR2, + inputCert: InvalidCert, + expectedErr: InvalidCertErr, + }, + { + inputCSR: ValidCSR1, + inputCert: ValidCert2, + expectedErr: certificateDoesNotMatchErr, + }, } - err = certdb.ValidateCertificate(ValidCert2, ValidCSR1) - if err == nil || err.Error() != "certificate does not match CSR" { - t.Fatalf("Expected cert to not match CSR") + + for i, c := range cases { + t.Run(fmt.Sprintf("InvalidCert%d", i), func(t *testing.T) { + err := certdb.ValidateCertificate(c.inputCert, c.inputCSR) + if err.Error() != c.expectedErr { + t.Fatalf("Expected error not found:\nReceived: %s\n Expected: %s", err, c.expectedErr) + } + }) } } - -// Fuzz test -// Examples From f36d64acbe6e4f9fb5a6f447d0c28dedddc4996d Mon Sep 17 00:00:00 2001 From: Kayra Date: Mon, 1 Apr 2024 14:53:07 +0300 Subject: [PATCH 13/16] errorf --- internal/certdb/validation_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/certdb/validation_test.go b/internal/certdb/validation_test.go index 02c54ce..deff30b 100644 --- a/internal/certdb/validation_test.go +++ b/internal/certdb/validation_test.go @@ -93,7 +93,7 @@ func TestCSRValidationSuccess(t *testing.T) { for i, c := range cases { t.Run(fmt.Sprintf("ValidCSR%d", i), func(t *testing.T) { if err := certdb.ValidateCertificateRequest(c); err != nil { - t.Fatalf("Couldn't verify valid CSR: %s", err) + t.Errorf("Couldn't verify valid CSR: %s", err) } }) } @@ -135,7 +135,7 @@ func TestCSRValidationFail(t *testing.T) { t.Run(fmt.Sprintf("InvalidCSR%d", i), func(t *testing.T) { err := certdb.ValidateCertificateRequest(c.input) if err.Error() != c.expectedErr { - t.Fatalf("Expected error not found:\nReceived: %s\nExpected: %s", err, c.expectedErr) + t.Errorf("Expected error not found:\nReceived: %s\nExpected: %s", err, c.expectedErr) } }) } @@ -147,7 +147,7 @@ func TestCertValidationSuccess(t *testing.T) { for i, c := range cases { t.Run(fmt.Sprintf("ValidCert%d", i), func(t *testing.T) { if err := certdb.ValidateCertificate(c, ValidCSR2); err != nil { - t.Fatalf("Couldn't verify valid Cert: %s", err) + t.Errorf("Couldn't verify valid Cert: %s", err) } }) } @@ -200,7 +200,7 @@ func TestCertValidationFail(t *testing.T) { t.Run(fmt.Sprintf("InvalidCert%d", i), func(t *testing.T) { err := certdb.ValidateCertificate(c.inputCert, c.inputCSR) if err.Error() != c.expectedErr { - t.Fatalf("Expected error not found:\nReceived: %s\n Expected: %s", err, c.expectedErr) + t.Errorf("Expected error not found:\nReceived: %s\n Expected: %s", err, c.expectedErr) } }) } From bafd1c2bb3a4e59089af20bcef65f42051188784 Mon Sep 17 00:00:00 2001 From: Kayra Date: Mon, 1 Apr 2024 16:30:02 +0300 Subject: [PATCH 14/16] no pointers --- internal/certdb/certdb.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index 397baf6..d554bcc 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -51,13 +51,16 @@ func (db *CertificateRequestsRepository) RetrieveAll() ([]CertificateRequest, er // Retrieve gets a given CSR from the repository. // It returns the row id and matching certificate alongside the CSR in a CertificateRequest object. -func (db *CertificateRequestsRepository) Retrieve(csr string) (*CertificateRequest, error) { +func (db *CertificateRequestsRepository) Retrieve(csr string) (CertificateRequest, error) { var newCSR CertificateRequest row := db.conn.QueryRow(fmt.Sprintf(queryGetCSR, db.table), csr) if err := row.Scan(&newCSR.ID, &newCSR.CSR, &newCSR.Certificate); err != nil { - return nil, err + newCSR.ID = -1 + newCSR.Certificate = "" + newCSR.CSR = "" + return newCSR, err } - return &newCSR, nil + return newCSR, nil } // Create creates a new entry in the repository. From 221f27b5d23e2e35d5d3685382f71ffa6a758c23 Mon Sep 17 00:00:00 2001 From: Kayra Date: Wed, 3 Apr 2024 10:18:44 +0300 Subject: [PATCH 15/16] remove unneeded lines --- internal/certdb/certdb.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index d554bcc..a88a9de 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -55,9 +55,6 @@ func (db *CertificateRequestsRepository) Retrieve(csr string) (CertificateReques var newCSR CertificateRequest row := db.conn.QueryRow(fmt.Sprintf(queryGetCSR, db.table), csr) if err := row.Scan(&newCSR.ID, &newCSR.CSR, &newCSR.Certificate); err != nil { - newCSR.ID = -1 - newCSR.Certificate = "" - newCSR.CSR = "" return newCSR, err } return newCSR, nil From 3d96fe08589e5939e84668a5b84aeb402923b318 Mon Sep 17 00:00:00 2001 From: Kayra Date: Wed, 3 Apr 2024 10:38:33 +0300 Subject: [PATCH 16/16] split certificate match function from validate function --- internal/certdb/certdb.go | 5 ++- internal/certdb/validation.go | 38 ++++++++++++++-------- internal/certdb/validation_test.go | 51 +++++++++++++++++++++++++----- 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/internal/certdb/certdb.go b/internal/certdb/certdb.go index a88a9de..297db38 100644 --- a/internal/certdb/certdb.go +++ b/internal/certdb/certdb.go @@ -80,7 +80,10 @@ func (db *CertificateRequestsRepository) Create(csr string) (int64, error) { // Update adds a new cert to the given CSR in the repository. // The given certificate must share the public key of the CSR and must be valid. func (db *CertificateRequestsRepository) Update(csr string, cert string) (int64, error) { - if err := ValidateCertificate(cert, csr); err != nil { + if err := ValidateCertificate(cert); err != nil { + return 0, err + } + if err := CertificateMatchesCSR(cert, csr); err != nil { return 0, err } result, err := db.conn.Exec(fmt.Sprintf(queryUpdateCSR, db.table), cert, csr) diff --git a/internal/certdb/validation.go b/internal/certdb/validation.go index fb1c759..9a487a4 100644 --- a/internal/certdb/validation.go +++ b/internal/certdb/validation.go @@ -10,8 +10,8 @@ import ( // ValidateCertificateRequest validates the given CSR string to the following: // The string must be a valid PEM string, and should be of type CERTIFICATE REQUEST // The PEM string should be able to be parsed into a x509 Certificate Request -func ValidateCertificateRequest(csrString string) error { - block, _ := pem.Decode([]byte(csrString)) +func ValidateCertificateRequest(csr string) error { + block, _ := pem.Decode([]byte(csr)) if block == nil { return errors.New("PEM Certificate Request string not found or malformed") } @@ -26,29 +26,39 @@ func ValidateCertificateRequest(csrString string) error { } // ValidateCertificate validates the given Cert string to the following: -// The given CSR must pass the validation provided by ValidateCertificateRequest // The cert string must be a valid PEM string, and should be of type CERTIFICATE // The PEM string should be able to be parsed into a x509 Certificate -// The given cert and CSR must share the same public key -func ValidateCertificate(certString string, csrString string) error { - if err := ValidateCertificateRequest(csrString); err != nil { - return err - } - csrBlock, _ := pem.Decode([]byte(csrString)) - csr, _ := x509.ParseCertificateRequest(csrBlock.Bytes) - certBlock, _ := pem.Decode([]byte(certString)) +func ValidateCertificate(cert string) error { + certBlock, _ := pem.Decode([]byte(cert)) if certBlock == nil { return errors.New("PEM Certificate string not found or malformed") } if certBlock.Type != "CERTIFICATE" { return errors.New("given PEM string not a certificate") } - cert, err := x509.ParseCertificate(certBlock.Bytes) + _, err := x509.ParseCertificate(certBlock.Bytes) if err != nil { return err } - certKey := cert.PublicKey.(*rsa.PublicKey) - csrKey := csr.PublicKey.(*rsa.PublicKey) + return nil +} + +// CertificateMatchesCSR makes sure that the given certificate and CSR match. +// The given CSR and Cert must pass their respective validation functions +// The given cert and CSR must share the same public key +func CertificateMatchesCSR(cert string, csr string) error { + if err := ValidateCertificateRequest(csr); err != nil { + return err + } + if err := ValidateCertificate(cert); err != nil { + return err + } + csrBlock, _ := pem.Decode([]byte(csr)) + parsedCSR, _ := x509.ParseCertificateRequest(csrBlock.Bytes) + certBlock, _ := pem.Decode([]byte(cert)) + parsedCERT, _ := x509.ParseCertificate(certBlock.Bytes) + certKey := parsedCERT.PublicKey.(*rsa.PublicKey) + csrKey := parsedCSR.PublicKey.(*rsa.PublicKey) if !csrKey.Equal(certKey) { return errors.New("certificate does not match CSR") } diff --git a/internal/certdb/validation_test.go b/internal/certdb/validation_test.go index deff30b..6e0940e 100644 --- a/internal/certdb/validation_test.go +++ b/internal/certdb/validation_test.go @@ -146,7 +146,7 @@ func TestCertValidationSuccess(t *testing.T) { for i, c := range cases { t.Run(fmt.Sprintf("ValidCert%d", i), func(t *testing.T) { - if err := certdb.ValidateCertificate(c, ValidCSR2); err != nil { + if err := certdb.ValidateCertificate(c); err != nil { t.Errorf("Couldn't verify valid Cert: %s", err) } }) @@ -162,33 +162,68 @@ func TestCertValidationFail(t *testing.T) { var wrongPemTypeErr = "given PEM string not a certificate" var InvalidCert = strings.ReplaceAll(ValidCert2, "M", "i") var InvalidCertErr = "x509: malformed certificate" - var certificateDoesNotMatchErr = "certificate does not match CSR" cases := []struct { - inputCSR string inputCert string expectedErr string }{ { - inputCSR: ValidCSR2, inputCert: wrongCertString, expectedErr: wrongCertStringErr, }, { - inputCSR: ValidCSR2, inputCert: ValidCertWithoutWhitespace, expectedErr: ValidCertWithoutWhitespaceErr, }, { - inputCSR: ValidCSR2, inputCert: wrongPemType, expectedErr: wrongPemTypeErr, }, { - inputCSR: ValidCSR2, inputCert: InvalidCert, expectedErr: InvalidCertErr, }, + } + + for i, c := range cases { + t.Run(fmt.Sprintf("InvalidCert%d", i), func(t *testing.T) { + err := certdb.ValidateCertificate(c.inputCert) + if err.Error() != c.expectedErr { + t.Errorf("Expected error not found:\nReceived: %s\n Expected: %s", err, c.expectedErr) + } + }) + } +} + +func TestCertificateMatchesCSRSuccess(t *testing.T) { + cases := []struct { + inputCSR string + inputCert string + }{ + { + inputCSR: ValidCSR2, + inputCert: ValidCert2, + }, + } + + for i, c := range cases { + t.Run(fmt.Sprintf("InvalidCert%d", i), func(t *testing.T) { + err := certdb.CertificateMatchesCSR(c.inputCert, c.inputCSR) + if err != nil { + t.Errorf("Certificate did not match when it should have") + } + }) + } +} + +func TestCertificateMatchesCSRFail(t *testing.T) { + var certificateDoesNotMatchErr = "certificate does not match CSR" + + cases := []struct { + inputCSR string + inputCert string + expectedErr string + }{ { inputCSR: ValidCSR1, inputCert: ValidCert2, @@ -198,7 +233,7 @@ func TestCertValidationFail(t *testing.T) { for i, c := range cases { t.Run(fmt.Sprintf("InvalidCert%d", i), func(t *testing.T) { - err := certdb.ValidateCertificate(c.inputCert, c.inputCSR) + err := certdb.CertificateMatchesCSR(c.inputCert, c.inputCSR) if err.Error() != c.expectedErr { t.Errorf("Expected error not found:\nReceived: %s\n Expected: %s", err, c.expectedErr) }