From 15ebffc85c8ade3b21fe20a487ba3bc4c2743267 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Mon, 2 Dec 2024 19:57:39 -0800 Subject: [PATCH 01/15] initial work --- cmd/keymasterd/roleRequestingCert.go | 191 +++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 cmd/keymasterd/roleRequestingCert.go diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go new file mode 100644 index 0000000..c299d5a --- /dev/null +++ b/cmd/keymasterd/roleRequestingCert.go @@ -0,0 +1,191 @@ +package main + +import ( + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" + "net" + "net/http" + "time" + + "github.com/Cloud-Foundations/keymaster/lib/certgen" + "github.com/Cloud-Foundations/keymaster/lib/instrumentedwriter" + "github.com/Cloud-Foundations/keymaster/lib/util" +) + +//const svcPrefixList= string ["svc-","role-"] + +const maxRoleRequestingCertDuration = time.Hour * 24 * 45 + +type roleRequestingCertGenParams struct { + Role string + Duration time.Duration + RequestorNetblocks []net.IPNet + UserPub interface{} + //targetNetblocks +} + +func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequestingCertGenParams, error, error) { + + logger.Debugf(3, "Got client POST connection") + err := r.ParseMultipartForm(1e7) + if err != nil { + state.logger.Println(err) + return nil, err, nil + } + var rvalue roleRequestingCertGenParams + /* + Role name: role + Public Key (PEM): pubkey + Requestor (Hypervisor) netblock: requestor_netblock + Target (VM) netblock: target_netblock + Optional duration: duration (i.e. 730h: :golang: time format) + */ + // Role + roleName := r.Form.Get("role") + if roleName == "" { + return nil, fmt.Errorf("Missing role parameter"), nil + } + ok, err := state.isAutomationUser(roleName) + if err != nil { + return nil, nil, err + } + if !ok { + return nil, fmt.Errorf("requested role is not automation user"), nil + //return "", time.Time{}, fmt.Errorf("Bad username for ip restricted cert"), nil + } + rvalue.Role = roleName + + //Duration + rvalue.Duration = maxRoleRequestingCertDuration + + //RequestorNetblocks + requestorNetblockStrings, ok := r.Form["requestor_netblock"] + if !ok { + return nil, fmt.Errorf("missing required requestor_netblock param"), nil + } + for _, netBlock := range requestorNetblockStrings { + _, parsedNetBlock, err := net.ParseCIDR(netBlock) + if err != nil { + state.logger.Printf("%s", err) + return nil, fmt.Errorf("invalid netblock"), nil + } + rvalue.RequestorNetblocks = append(rvalue.RequestorNetblocks, *parsedNetBlock) + } + // publickey + b64pubkey := r.Form.Get("pubkey") + if b64pubkey == "" { + return nil, fmt.Errorf("Missing pubkey parameter"), nil + } + pkixDerPub, err := base64.URLEncoding.DecodeString(b64pubkey) + if err != nil { + state.logger.Printf("%s", err) + return nil, fmt.Errorf("Invalid encoding for pubkey"), nil + } + userPub, err := x509.ParsePKIXPublicKey(pkixDerPub) + if err != nil { + state.logger.Printf("%s", err) + return nil, fmt.Errorf("pubkey is not valid PKIX public key"), nil + } + // TODO: validate key strength + rvalue.UserPub = userPub + + return &rvalue, nil, nil + //return nil, nil, fmt.Errorf("not implemented") +} + +func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { + var signerIsNull bool + //var keySigner crypto.Signer + + // copy runtime singer if not nil + state.Mutex.Lock() + signerIsNull = (state.Signer == nil) + /* + if !signerIsNull { + keySigner = state.Signer + } + */ + state.Mutex.Unlock() + + //local sanity tests + if signerIsNull { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + logger.Printf("Signer not loaded") + return + } + + authData, err := state.checkAuth(w, r, + state.getRequiredWebUIAuthLevel()|AuthTypeKeymasterX509) + if err != nil { + state.logger.Debugf(1, "%v", err) + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + return + } + w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username) + + // TODO: this should be a different check, for now keep it to admin users + if !state.IsAdminUser(authData.Username) { + state.writeFailureResponse(w, r, http.StatusUnauthorized, + "Not an admin user") + return + } + // + /// Now we parse the inputs + if r.Method != "POST" { + state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "") + return + } + params, userError, err := state.parseRoleCertGenParams(r) + if err != nil { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + return + } + if userError != nil { + state.writeFailureResponse(w, r, http.StatusBadRequest, + userError.Error()) + return + } + signer, caCertDer, err := state.getSignerX509CAForPublic(params.UserPub) + if err != nil { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + logger.Printf("Error Finding Cert for public key: %s\n data", err) + return + } + caCert, err := x509.ParseCertificate(caCertDer) + if err != nil { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + logger.Printf("Cannot parse CA Der: %s\n data", err) + return + } + + derCert, err := certgen.GenIPRestrictedX509Cert(params.Role, params.UserPub, + caCert, signer, params.RequestorNetblocks, params.Duration, nil, nil) + + if err != nil { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + logger.Printf("Cannot Parse Generated x509cert: %s\n", err) + return + } + parsedCert, err := x509.ParseCertificate(derCert) + if err != nil { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + logger.Printf("Cannot Parse Generated x509cert: %s\n", err) + return + } + + eventNotifier.PublishX509(derCert) + cert := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", + Bytes: derCert})) + + // add logging + metrics + clientIpAddress := util.GetRequestRealIp(r) + + w.Header().Set("Content-Disposition", `attachment; filename="userCert.pem"`) + w.WriteHeader(200) + fmt.Fprintf(w, "%s", cert) + logger.Printf("Generated x509 role Requesting Certificate for %s (from %s). Serial: %s", + params.Role, clientIpAddress, parsedCert.SerialNumber.String()) + +} From c1f841660a1a00a847213d239264be54f6a9f713 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Tue, 3 Dec 2024 11:30:33 -0800 Subject: [PATCH 02/15] initial tests --- cmd/keymasterd/app.go | 1 + cmd/keymasterd/config.go | 1 + cmd/keymasterd/roleRequestingCert.go | 78 +++++++++++++++++------ cmd/keymasterd/roleRequestingCert_test.go | 54 ++++++++++++++++ 4 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 cmd/keymasterd/roleRequestingCert_test.go diff --git a/cmd/keymasterd/app.go b/cmd/keymasterd/app.go index 8d883c9..c65aad9 100644 --- a/cmd/keymasterd/app.go +++ b/cmd/keymasterd/app.go @@ -1937,6 +1937,7 @@ func main() { serviceMux.HandleFunc(paths.VerifyAuthToken, runtimeState.VerifyAuthTokenHandler) } + serviceMux.HandleFunc(getRoleRequestingPath, runtimeState.roleRequetingCertGenHandler) serviceMux.HandleFunc("/", runtimeState.defaultPathHandler) cfg := &tls.Config{ diff --git a/cmd/keymasterd/config.go b/cmd/keymasterd/config.go index bd45653..4fb2891 100644 --- a/cmd/keymasterd/config.go +++ b/cmd/keymasterd/config.go @@ -91,6 +91,7 @@ type baseConfig struct { SecsBetweenDependencyChecks int `yaml:"secs_between_dependency_checks"` AutomationUserGroups []string `yaml:"automation_user_groups"` AutomationUsers []string `yaml:"automation_users"` + AutomationAdmins []string `yaml:"automation_admins"` DisableUsernameNormalization bool `yaml:"disable_username_normalization"` EnableLocalTOTP bool `yaml:"enable_local_totp"` EnableBootstrapOTP bool `yaml:"enable_bootstrapotp"` diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index c299d5a..58b8c3e 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -16,6 +16,7 @@ import ( //const svcPrefixList= string ["svc-","role-"] +const getRoleRequestingPath = "/v1/getRoleRequestingCert" const maxRoleRequestingCertDuration = time.Hour * 24 * 45 type roleRequestingCertGenParams struct { @@ -23,11 +24,9 @@ type roleRequestingCertGenParams struct { Duration time.Duration RequestorNetblocks []net.IPNet UserPub interface{} - //targetNetblocks } func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequestingCertGenParams, error, error) { - logger.Debugf(3, "Got client POST connection") err := r.ParseMultipartForm(1e7) if err != nil { @@ -73,6 +72,20 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest } rvalue.RequestorNetblocks = append(rvalue.RequestorNetblocks, *parsedNetBlock) } + //TargetNetblocks + targetNetblockStrings, ok := r.Form["target_netblock"] + if !ok { + return nil, fmt.Errorf("missing required requestor_netblock param"), nil + } + for _, netBlock := range targetNetblockStrings { + _, _, err := net.ParseCIDR(netBlock) + if err != nil { + state.logger.Printf("%s", err) + return nil, fmt.Errorf("invalid netblock %s", netBlock), nil + } + //rvalue.RequestorNetblocks = append(rvalue.RequestorNetblocks, *parsedNetBlock) + } + // publickey b64pubkey := r.Form.Get("pubkey") if b64pubkey == "" { @@ -88,11 +101,30 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest state.logger.Printf("%s", err) return nil, fmt.Errorf("pubkey is not valid PKIX public key"), nil } - // TODO: validate key strength + validKey, err := certgen.ValidatePublicKeyStrength(userPub) + if err != nil { + return nil, nil, err + } + if !validKey { + return nil, fmt.Errorf("Invalid File, Check Key strength/key type"), nil + } rvalue.UserPub = userPub return &rvalue, nil, nil - //return nil, nil, fmt.Errorf("not implemented") +} + +func (state *RuntimeState) isAutomationAdmin(user string) bool { + isAdmin := state.IsAdminUser(user) + if isAdmin { + return true + } + for _, adminUser := range state.Config.Base.AutomationAdmins { + if user == adminUser { + return true + } + } + return false + } func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { @@ -126,12 +158,15 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username) // TODO: this should be a different check, for now keep it to admin users - if !state.IsAdminUser(authData.Username) { + if !state.isAutomationAdmin(authData.Username) { state.writeFailureResponse(w, r, http.StatusUnauthorized, "Not an admin user") return } + + // TODO: maybe add a check to ensure role certs cannot get role certs? // + /// Now we parse the inputs if r.Method != "POST" { state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "") @@ -147,32 +182,38 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r userError.Error()) return } - signer, caCertDer, err := state.getSignerX509CAForPublic(params.UserPub) + message, code, err := state.postAuthRoleRequetingCertGenProcessor(w, r, params) if err != nil { - state.writeFailureResponse(w, r, http.StatusInternalServerError, "") - logger.Printf("Error Finding Cert for public key: %s\n data", err) + state.writeFailureResponse(w, r, code, message) + if code >= 500 { + state.logger.Printf("Error generating cert", err) + } return } + +} +func (state *RuntimeState) postAuthRoleRequetingCertGenProcessor(w http.ResponseWriter, r *http.Request, params *roleRequestingCertGenParams) (string, int, error) { + signer, caCertDer, err := state.getSignerX509CAForPublic(params.UserPub) + if err != nil { + return "", http.StatusInternalServerError, fmt.Errorf("Error Finding Cert for public key: %s\n data", err) + //state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + //state.logger.Printf("Error Finding Cert for public key: %s\n data", err) + //return + } caCert, err := x509.ParseCertificate(caCertDer) if err != nil { - state.writeFailureResponse(w, r, http.StatusInternalServerError, "") - logger.Printf("Cannot parse CA Der: %s\n data", err) - return + return "", http.StatusInternalServerError, fmt.Errorf("Cannot parse CA Der: %s\n data", err) } derCert, err := certgen.GenIPRestrictedX509Cert(params.Role, params.UserPub, caCert, signer, params.RequestorNetblocks, params.Duration, nil, nil) if err != nil { - state.writeFailureResponse(w, r, http.StatusInternalServerError, "") - logger.Printf("Cannot Parse Generated x509cert: %s\n", err) - return + return "", http.StatusInternalServerError, fmt.Errorf("Cannot Generate x509cert: %s\n", err) } parsedCert, err := x509.ParseCertificate(derCert) if err != nil { - state.writeFailureResponse(w, r, http.StatusInternalServerError, "") - logger.Printf("Cannot Parse Generated x509cert: %s\n", err) - return + return "", http.StatusInternalServerError, fmt.Errorf("Cannot Parse Generated x509cert: %s\n", err) } eventNotifier.PublishX509(derCert) @@ -185,7 +226,8 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r w.Header().Set("Content-Disposition", `attachment; filename="userCert.pem"`) w.WriteHeader(200) fmt.Fprintf(w, "%s", cert) - logger.Printf("Generated x509 role Requesting Certificate for %s (from %s). Serial: %s", + state.logger.Printf("Generated x509 role Requesting Certificate for %s (from %s). Serial: %s", params.Role, clientIpAddress, parsedCert.SerialNumber.String()) + return "", 200, nil } diff --git a/cmd/keymasterd/roleRequestingCert_test.go b/cmd/keymasterd/roleRequestingCert_test.go new file mode 100644 index 0000000..7bfc0e5 --- /dev/null +++ b/cmd/keymasterd/roleRequestingCert_test.go @@ -0,0 +1,54 @@ +package main + +import ( + "encoding/base64" + "encoding/pem" + "net/http" + "net/url" + "os" + "strconv" + "strings" + "testing" +) + +func TestParseRoleCertGenParams(t *testing.T) { + state, passwdFile, err := setupValidRuntimeStateSigner(t) + if err != nil { + t.Fatal(err) + } + defer os.Remove(passwdFile.Name()) // clean up + + // + state.Config.Base.AutomationUsers = append(state.Config.Base.AutomationUsers, "role1") + state.Config.Base.AutomationAdmins = append(state.Config.Base.AutomationAdmins, "admin1") + + //first pass everything OK + + userPemBlock, _ := pem.Decode([]byte(testUserPEMPublicKey)) + b64public := base64.RawURLEncoding.EncodeToString(userPemBlock.Bytes) + + form := url.Values{} + form.Add("identity", "role1") + form.Add("requestor_netblock", "127.0.0.1/32") + form.Add("pubkey", b64public) + form.Add("target_netblock", "192.168.0.174/32") + + //form.Add("password", validPasswordConst) + + req, err := http.NewRequest("POST", getRoleRequestingPath, strings.NewReader(form.Encode())) + if err != nil { + t.Fatal(err) + } + //req.AddCookie(&authCookie) + req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode()))) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + _, userErr, err := state.parseRoleCertGenParams(req) + if err != nil { + t.Fatal(err) + } + if userErr != nil { + t.Fatal(userErr) + } + +} From fc02cbb1fc21b7ee495ff6f7c5a26a485b076516 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Tue, 3 Dec 2024 11:30:49 -0800 Subject: [PATCH 03/15] unify encoding --- cmd/keymasterd/roleRequestingCert.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index 58b8c3e..cd30749 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -28,7 +28,7 @@ type roleRequestingCertGenParams struct { func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequestingCertGenParams, error, error) { logger.Debugf(3, "Got client POST connection") - err := r.ParseMultipartForm(1e7) + err := r.ParseForm() if err != nil { state.logger.Println(err) return nil, err, nil @@ -42,9 +42,9 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest Optional duration: duration (i.e. 730h: :golang: time format) */ // Role - roleName := r.Form.Get("role") + roleName := r.Form.Get("identity") if roleName == "" { - return nil, fmt.Errorf("Missing role parameter"), nil + return nil, fmt.Errorf("Missing identity parameter"), nil } ok, err := state.isAutomationUser(roleName) if err != nil { @@ -91,7 +91,7 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest if b64pubkey == "" { return nil, fmt.Errorf("Missing pubkey parameter"), nil } - pkixDerPub, err := base64.URLEncoding.DecodeString(b64pubkey) + pkixDerPub, err := base64.RawURLEncoding.DecodeString(b64pubkey) if err != nil { state.logger.Printf("%s", err) return nil, fmt.Errorf("Invalid encoding for pubkey"), nil From c915638eaf60de07c13d6b66ad4575eed821a3d9 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Tue, 3 Dec 2024 14:02:12 -0800 Subject: [PATCH 04/15] new endpoint not tested at all --- cmd/keymasterd/roleRequestingCert.go | 132 +++++++++++++++++++++++++++ lib/certgen/iprestricted.go | 39 +++++++- 2 files changed, 169 insertions(+), 2 deletions(-) diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index cd30749..98dbdb8 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -231,3 +231,135 @@ func (state *RuntimeState) postAuthRoleRequetingCertGenProcessor(w http.Response return "", 200, nil } + +func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r *http.Request) (*roleRequestingCertGenParams, error, error) { + + logger.Debugf(3, "Got client POST connection") + err := r.ParseForm() + if err != nil { + state.logger.Println(err) + return nil, err, nil + } + var rvalue roleRequestingCertGenParams + /* + Role name: role + Public Key (PEM): pubkey + Requestor (Hypervisor) netblock: requestor_netblock + Target (VM) netblock: target_netblock + Optional duration: duration (i.e. 730h: :golang: time format) + */ + // Role + + identityName := authData.Username + if identityName == "" { + return nil, fmt.Errorf("Missing identity parameter"), nil + } + ok, err := state.isAutomationUser(identityName) + if err != nil { + return nil, nil, err + } + if !ok { + return nil, fmt.Errorf("requested role is not automation user"), nil + //return "", time.Time{}, fmt.Errorf("Bad username for ip restricted cert"), nil + } + rvalue.Role = identityName + + //Duration + rvalue.Duration = maxRoleRequestingCertDuration + + // publickey + b64pubkey := r.Form.Get("pubkey") + if b64pubkey == "" { + return nil, fmt.Errorf("Missing pubkey parameter"), nil + } + pkixDerPub, err := base64.RawURLEncoding.DecodeString(b64pubkey) + if err != nil { + state.logger.Printf("%s", err) + return nil, fmt.Errorf("Invalid encoding for pubkey"), nil + } + userPub, err := x509.ParsePKIXPublicKey(pkixDerPub) + if err != nil { + state.logger.Printf("%s", err) + return nil, fmt.Errorf("pubkey is not valid PKIX public key"), nil + } + validKey, err := certgen.ValidatePublicKeyStrength(userPub) + if err != nil { + return nil, nil, err + } + if !validKey { + return nil, fmt.Errorf("Invalid File, Check Key strength/key type"), nil + } + rvalue.UserPub = userPub + + // networks + if r.TLS == nil { + return nil, fmt.Errorf("MUST only come form certificate"), nil + } + if len(r.TLS.VerifiedChains) < 1 { + return nil, fmt.Errorf("MUST only come form certificate"), nil + } + userCert := r.TLS.VerifiedChains[0][0] + certNets, err := certgen.ExtractIPNetsFromIPRestrictedX509(userCert) + if err != nil { + return nil, nil, err + } + rvalue.RequestorNetblocks = certNets + return &rvalue, nil, nil +} + +func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { + + var signerIsNull bool + //var keySigner crypto.Signer + + // copy runtime singer if not nil + state.Mutex.Lock() + signerIsNull = (state.Signer == nil) + /* + if !signerIsNull { + keySigner = state.Signer + } + */ + state.Mutex.Unlock() + + //local sanity tests + if signerIsNull { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + logger.Printf("Signer not loaded") + return + } + + authData, err := state.checkAuth(w, r, AuthTypeIPCertificate) + if err != nil { + state.logger.Debugf(1, "%v", err) + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + return + } + // TODO: we need to do denylist checks here against the cert/certkey + + w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username) + + /// Now we parse the inputs + if r.Method != "POST" { + state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "") + return + } + params, userError, err := state.parseRefreshRoleCertGenParams(authData, r) + if err != nil { + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + return + } + if userError != nil { + state.writeFailureResponse(w, r, http.StatusBadRequest, + userError.Error()) + return + } + message, code, err := state.postAuthRoleRequetingCertGenProcessor(w, r, params) + if err != nil { + state.writeFailureResponse(w, r, code, message) + if code >= 500 { + state.logger.Printf("Error generating cert", err) + } + return + } +} diff --git a/lib/certgen/iprestricted.go b/lib/certgen/iprestricted.go index 46f75c9..dc64e9f 100644 --- a/lib/certgen/iprestricted.go +++ b/lib/certgen/iprestricted.go @@ -9,6 +9,8 @@ import ( "crypto/x509/pkix" "encoding/asn1" "errors" + "fmt" + //"log" "math/big" "net" @@ -26,7 +28,7 @@ type IpAdressFamily struct { var oidIPAddressDelegation = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 7} var ipV4FamilyEncoding = []byte{0, 1, 1} -//For now ipv4 only +// For now ipv4 only func encodeIpAddressChoice(netBlock net.IPNet) (asn1.BitString, error) { ones, bits := netBlock.Mask.Size() if bits != 32 { @@ -90,7 +92,6 @@ func decodeIPV4AddressChoice(encodedBlock asn1.BitString) (net.IPNet, error) { return netBlock, nil } -// type subjectPublicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier SubjectPublicKey asn1.BitString @@ -195,3 +196,37 @@ func VerifyIPRestrictedX509CertIP(userCert *x509.Certificate, remoteAddr string) } return false, nil } + +func ExtractIPNetsFromIPRestrictedX509(userCert *x509.Certificate) ([]net.IPNet, error) { + var extension *pkix.Extension = nil + var err error + for _, certExtension := range userCert.Extensions { + if certExtension.Id.Equal(oidIPAddressDelegation) { + extension = &certExtension + break + } + } + if extension == nil { + return nil, fmt.Errorf("externsion not found") + } + var ipAddressFamilyList []IpAdressFamily + _, err = asn1.Unmarshal(extension.Value, &ipAddressFamilyList) + if err != nil { + return nil, err + } + var rvalue []net.IPNet + for _, addressList := range ipAddressFamilyList { + if !bytes.Equal(addressList.AddressFamily, ipV4FamilyEncoding) { + //continue + return nil, fmt.Errorf("We only support ipv4 netblocks") + } + for _, encodedNetblock := range addressList.Addresses { + decoded, err := decodeIPV4AddressChoice(encodedNetblock) + if err != nil { + return nil, err + } + rvalue = append(rvalue, decoded) + } + } + return rvalue, nil +} From 1351cf3500ef2c47b6141fa8ecf9e1e1d83265f5 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Tue, 3 Dec 2024 14:56:49 -0800 Subject: [PATCH 05/15] initial tests of rt --- cmd/keymasterd/roleRequestingCert.go | 73 +++++++------ cmd/keymasterd/roleRequestingCert_test.go | 122 ++++++++++++++++++++++ 2 files changed, 162 insertions(+), 33 deletions(-) diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index 98dbdb8..1394355 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -27,7 +27,7 @@ type roleRequestingCertGenParams struct { } func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequestingCertGenParams, error, error) { - logger.Debugf(3, "Got client POST connection") + state.logger.Debugf(3, "Got client POST connection") err := r.ParseForm() if err != nil { state.logger.Println(err) @@ -144,7 +144,7 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r //local sanity tests if signerIsNull { state.writeFailureResponse(w, r, http.StatusInternalServerError, "") - logger.Printf("Signer not loaded") + state.logger.Printf("Signer not loaded") return } @@ -182,64 +182,61 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r userError.Error()) return } - message, code, err := state.postAuthRoleRequetingCertGenProcessor(w, r, params) + pemCert, cert, err := state.withParamsGenegneratRoleRequetingCert(params) if err != nil { - state.writeFailureResponse(w, r, code, message) - if code >= 500 { - state.logger.Printf("Error generating cert", err) - } + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + state.logger.Printf("Error generating cert", err) return } + clientIpAddress := util.GetRequestRealIp(r) + + w.Header().Set("Content-Disposition", `attachment; filename="roleRequstingCert.pem"`) + w.WriteHeader(200) + fmt.Fprintf(w, "%s", pemCert) + state.logger.Printf("Generated x509 role Requesting Certificate for %s (from %s). Serial: %s", + params.Role, clientIpAddress, cert.SerialNumber.String()) + + return } -func (state *RuntimeState) postAuthRoleRequetingCertGenProcessor(w http.ResponseWriter, r *http.Request, params *roleRequestingCertGenParams) (string, int, error) { +func (state *RuntimeState) withParamsGenegneratRoleRequetingCert(params *roleRequestingCertGenParams) (string, *x509.Certificate, error) { signer, caCertDer, err := state.getSignerX509CAForPublic(params.UserPub) if err != nil { - return "", http.StatusInternalServerError, fmt.Errorf("Error Finding Cert for public key: %s\n data", err) - //state.writeFailureResponse(w, r, http.StatusInternalServerError, "") - //state.logger.Printf("Error Finding Cert for public key: %s\n data", err) - //return + return "", nil, fmt.Errorf("Error Finding Cert for public key: %s\n data", err) } caCert, err := x509.ParseCertificate(caCertDer) if err != nil { - return "", http.StatusInternalServerError, fmt.Errorf("Cannot parse CA Der: %s\n data", err) + return "", nil, fmt.Errorf("Cannot parse CA Der: %s\n data", err) } derCert, err := certgen.GenIPRestrictedX509Cert(params.Role, params.UserPub, caCert, signer, params.RequestorNetblocks, params.Duration, nil, nil) if err != nil { - return "", http.StatusInternalServerError, fmt.Errorf("Cannot Generate x509cert: %s\n", err) + return "", nil, fmt.Errorf("Cannot Generate x509cert: %s\n", err) } parsedCert, err := x509.ParseCertificate(derCert) if err != nil { - return "", http.StatusInternalServerError, fmt.Errorf("Cannot Parse Generated x509cert: %s\n", err) + return "", nil, fmt.Errorf("Cannot Parse Generated x509cert: %s\n", err) } eventNotifier.PublishX509(derCert) cert := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derCert})) + return cert, parsedCert, nil - // add logging + metrics - clientIpAddress := util.GetRequestRealIp(r) - - w.Header().Set("Content-Disposition", `attachment; filename="userCert.pem"`) - w.WriteHeader(200) - fmt.Fprintf(w, "%s", cert) - state.logger.Printf("Generated x509 role Requesting Certificate for %s (from %s). Serial: %s", - params.Role, clientIpAddress, parsedCert.SerialNumber.String()) - - return "", 200, nil } func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r *http.Request) (*roleRequestingCertGenParams, error, error) { - logger.Debugf(3, "Got client POST connection") + state.logger.Debugf(4, "Got client POST connection") err := r.ParseForm() if err != nil { state.logger.Println(err) return nil, err, nil } + state.logger.Debugf(4, "parseRefreshRoleCertGenParams past postform r=%+v", r) + var rvalue roleRequestingCertGenParams /* Role name: role @@ -268,7 +265,7 @@ func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r * rvalue.Duration = maxRoleRequestingCertDuration // publickey - b64pubkey := r.Form.Get("pubkey") + b64pubkey := r.PostForm.Get("pubkey") if b64pubkey == "" { return nil, fmt.Errorf("Missing pubkey parameter"), nil } @@ -325,10 +322,11 @@ func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWri //local sanity tests if signerIsNull { state.writeFailureResponse(w, r, http.StatusInternalServerError, "") - logger.Printf("Signer not loaded") + state.logger.Printf("Signer not loaded") return } + state.logger.Debugf(1, "refreshRoleRequetingCertGenHandler before auth") authData, err := state.checkAuth(w, r, AuthTypeIPCertificate) if err != nil { state.logger.Debugf(1, "%v", err) @@ -336,6 +334,7 @@ func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWri return } // TODO: we need to do denylist checks here against the cert/certkey + state.logger.Debugf(1, "refreshRoleRequetingCertGenHandler: authenticated") w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username) @@ -350,16 +349,24 @@ func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWri return } if userError != nil { + state.logger.Debugf(1, "refreshRoleRequetingCertGenHandler: error parsing params err=%s", userError) state.writeFailureResponse(w, r, http.StatusBadRequest, userError.Error()) return } - message, code, err := state.postAuthRoleRequetingCertGenProcessor(w, r, params) + pemCert, cert, err := state.withParamsGenegneratRoleRequetingCert(params) if err != nil { - state.writeFailureResponse(w, r, code, message) - if code >= 500 { - state.logger.Printf("Error generating cert", err) - } + state.writeFailureResponse(w, r, http.StatusInternalServerError, "") + state.logger.Printf("Error generating cert", err) return } + clientIpAddress := util.GetRequestRealIp(r) + + w.Header().Set("Content-Disposition", `attachment; filename="roleRequstingCert.pem"`) + w.WriteHeader(200) + fmt.Fprintf(w, "%s", pemCert) + state.logger.Printf("Generated x509 role Requesting Certificate for %s (from %s). Serial: %s", + params.Role, clientIpAddress, cert.SerialNumber.String()) + + return } diff --git a/cmd/keymasterd/roleRequestingCert_test.go b/cmd/keymasterd/roleRequestingCert_test.go index 7bfc0e5..fd35066 100644 --- a/cmd/keymasterd/roleRequestingCert_test.go +++ b/cmd/keymasterd/roleRequestingCert_test.go @@ -1,14 +1,21 @@ package main import ( + "crypto/tls" + "crypto/x509" "encoding/base64" "encoding/pem" + "io/ioutil" + "net" "net/http" "net/url" "os" "strconv" "strings" "testing" + "time" + + "github.com/Cloud-Foundations/keymaster/lib/webapi/v0/proto" ) func TestParseRoleCertGenParams(t *testing.T) { @@ -52,3 +59,118 @@ func TestParseRoleCertGenParams(t *testing.T) { } } + +func TestRoleRequetingCertGenHandler(t *testing.T) { + state, passwdFile, err := setupValidRuntimeStateSigner(t) + if err != nil { + t.Fatal(err) + } + defer os.Remove(passwdFile.Name()) // clean up + + // + state.Config.Base.AutomationUsers = append(state.Config.Base.AutomationUsers, "role1") + state.Config.Base.AutomationAdmins = append(state.Config.Base.AutomationAdmins, "admin1") + state.Config.Base.AllowedAuthBackendsForCerts = append(state.Config.Base.AllowedAuthBackendsForCerts, proto.AuthTypePassword) + state.Config.Base.AllowedAuthBackendsForWebUI = []string{"password"} + + userPemBlock, _ := pem.Decode([]byte(testUserPEMPublicKey)) + b64public := base64.RawURLEncoding.EncodeToString(userPemBlock.Bytes) + form := url.Values{} + form.Add("identity", "role1") + form.Add("requestor_netblock", "127.0.0.1/32") + form.Add("pubkey", b64public) + form.Add("target_netblock", "192.168.0.174/32") + + req, err := http.NewRequest("POST", getRoleRequestingPath, strings.NewReader(form.Encode())) + if err != nil { + t.Fatal(err) + } + + cookieVal, err := state.setNewAuthCookie(nil, "admin1", AuthTypePassword) + if err != nil { + t.Fatal(err) + } + authCookie := http.Cookie{Name: authCookieName, Value: cookieVal} + req.AddCookie(&authCookie) + req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode()))) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + rr, err := checkRequestHandlerCode(req, state.roleRequetingCertGenHandler, http.StatusOK) + if err != nil { + t.Fatal(err) + } + + resp := rr.Result() + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + // TODO: check body content is actually pem +} + +func TestRefreshRoleRequetingCertGenHandler(t *testing.T) { + state, passwdFile, err := setupValidRuntimeStateSigner(t) + if err != nil { + t.Fatal(err) + } + defer os.Remove(passwdFile.Name()) // clean up + + // + state.Config.Base.AutomationUsers = append(state.Config.Base.AutomationUsers, "role1") + state.Config.Base.AutomationAdmins = append(state.Config.Base.AutomationAdmins, "admin1") + state.Config.Base.AllowedAuthBackendsForCerts = append(state.Config.Base.AllowedAuthBackendsForCerts, proto.AuthTypePassword) + state.Config.Base.AllowedAuthBackendsForWebUI = []string{"password"} + + userPub, err := getPubKeyFromPem(testUserPEMPublicKey) + if err != nil { + t.Fatal(err) + } + netblock := net.IPNet{ + IP: net.ParseIP("127.0.0.0"), + Mask: net.CIDRMask(8, 32), + } + netblock2 := net.IPNet{ + IP: net.ParseIP("10.0.0.0"), + Mask: net.CIDRMask(8, 32), + } + netblockList := []net.IPNet{netblock, netblock2} + + initialrrParams := roleRequestingCertGenParams{ + Role: "role1", + Duration: time.Hour, + RequestorNetblocks: netblockList, + UserPub: userPub, + } + _, rrcert, err := state.withParamsGenegneratRoleRequetingCert(&initialrrParams) + if err != nil { + t.Fatal(err) + } + + userPemBlock, _ := pem.Decode([]byte(testUserPEMPublicKey)) + b64public := base64.RawURLEncoding.EncodeToString(userPemBlock.Bytes) + form := url.Values{} + form.Add("pubkey", b64public) + + req, err := http.NewRequest("POST", getRoleRequestingPath, strings.NewReader(form.Encode())) + if err != nil { + t.Fatal(err) + } + req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode()))) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.RemoteAddr = "127.0.0.1:12345" + var fakePeerCertificates []*x509.Certificate + var fakeVerifiedChains [][]*x509.Certificate + fakePeerCertificates = append(fakePeerCertificates, rrcert) + fakeVerifiedChains = append(fakeVerifiedChains, fakePeerCertificates) + connectionState := &tls.ConnectionState{ + VerifiedChains: fakeVerifiedChains, + PeerCertificates: fakePeerCertificates} + req.TLS = connectionState + + //TODO add fail value + _, err = checkRequestHandlerCode(req, state.refreshRoleRequetingCertGenHandler, http.StatusOK) + if err != nil { + t.Fatal(err) + } + +} From 9037203951c9fb4b49a2b2f02ea6e41ff4831b85 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Tue, 3 Dec 2024 15:31:05 -0800 Subject: [PATCH 06/15] adding test for iprestricted --- Makefile | 2 +- cmd/keymasterd/app.go | 1 + cmd/keymasterd/roleRequestingCert.go | 1 + lib/certgen/iprestricted_test.go | 33 ++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c1b9024..14ddee5 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ endif BINARY=keymaster # These are the values we want to pass for Version and BuildTime -VERSION?=1.15.5 +VERSION?=1.15.6 DEFAULT_HOST?= VERSION_FLAVOUR?= EXTRA_LDFLAGS?= diff --git a/cmd/keymasterd/app.go b/cmd/keymasterd/app.go index c65aad9..ca4458e 100644 --- a/cmd/keymasterd/app.go +++ b/cmd/keymasterd/app.go @@ -1938,6 +1938,7 @@ func main() { runtimeState.VerifyAuthTokenHandler) } serviceMux.HandleFunc(getRoleRequestingPath, runtimeState.roleRequetingCertGenHandler) + serviceMux.HandleFunc(refreshRoleRequestingCertPath, runtimeState.refreshRoleRequetingCertGenHandler) serviceMux.HandleFunc("/", runtimeState.defaultPathHandler) cfg := &tls.Config{ diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index 1394355..f892a97 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -17,6 +17,7 @@ import ( //const svcPrefixList= string ["svc-","role-"] const getRoleRequestingPath = "/v1/getRoleRequestingCert" +const refreshRoleRequestingCertPath = "/v1/refreshRoleRequestingCert" const maxRoleRequestingCertDuration = time.Hour * 24 * 45 type roleRequestingCertGenParams struct { diff --git a/lib/certgen/iprestricted_test.go b/lib/certgen/iprestricted_test.go index f1d5fff..6c3c6bf 100644 --- a/lib/certgen/iprestricted_test.go +++ b/lib/certgen/iprestricted_test.go @@ -104,3 +104,36 @@ func TestGenIPRestrictedX509Cert(t *testing.T) { t.Fatal("should have failed extension not found") } } + +func TestExtractIPNetsFromIPRestrictedX509(t *testing.T) { + userPub, caCert, caPriv := setupX509Generator(t) + netblock := net.IPNet{ + IP: net.ParseIP("127.0.0.0"), + Mask: net.CIDRMask(8, 32), + } + netblock2 := net.IPNet{ + IP: net.ParseIP("10.0.0.0"), + Mask: net.CIDRMask(8, 32), + } + netblockList := []net.IPNet{netblock, netblock2} + derCert, err := GenIPRestrictedX509Cert("username", userPub, caCert, caPriv, netblockList, testDuration, nil, nil) + if err != nil { + t.Fatal(err) + } + cert, _, err := derBytesCertToCertAndPem(derCert) + if err != nil { + t.Fatal(err) + } + certNets, err := ExtractIPNetsFromIPRestrictedX509(cert) + if err != nil { + t.Fatal(err) + } + if len(certNets) != len(netblockList) { + t.Fatalf("lenghts should match") + } + for i, certNet := range certNets { + if certNet.String() != netblockList[i].String() { + t.Fatalf("nets dont match") + } + } +} From ed29688ec0b6618d808303cad4af4d74b835579b Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Tue, 3 Dec 2024 16:54:41 -0800 Subject: [PATCH 07/15] minor hack --- cmd/keymasterd/certgen.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/keymasterd/certgen.go b/cmd/keymasterd/certgen.go index f7fa593..2efab68 100644 --- a/cmd/keymasterd/certgen.go +++ b/cmd/keymasterd/certgen.go @@ -101,6 +101,11 @@ func (state *RuntimeState) certGenHandler(w http.ResponseWriter, r *http.Request sufficientAuthLevel = true } } + // temporary hack + if (authData.AuthType & AuthTypeKeymasterX509) == AuthTypeKeymasterX509 { + sufficientAuthLevel = true + } + // if you have u2f you can always get the cert if (authData.AuthType & AuthTypeU2F) == AuthTypeU2F { sufficientAuthLevel = true From 0d500a87074d213341ca21af3e09be0d7ae3c0a2 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Wed, 4 Dec 2024 09:12:19 -0800 Subject: [PATCH 08/15] hack removal --- cmd/keymasterd/app.go | 56 ++++++++++++++++------------ cmd/keymasterd/certgen.go | 6 +-- cmd/keymasterd/roleRequestingCert.go | 6 --- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/cmd/keymasterd/app.go b/cmd/keymasterd/app.go index ca4458e..d4b1409 100644 --- a/cmd/keymasterd/app.go +++ b/cmd/keymasterd/app.go @@ -869,36 +869,46 @@ func (state *RuntimeState) checkAuth(w http.ResponseWriter, r *http.Request, req state.logger.Debugf(3, "looks like authtype tls keymaster or ip cert, r.tls=%+v", r.TLS) if len(r.TLS.VerifiedChains) > 0 { - if (requiredAuthType & AuthTypeKeymasterX509) != 0 { - tlsAuthUser, notBefore, err := - state.getUsernameIfKeymasterSigned(r.TLS.VerifiedChains) - if err == nil && tlsAuthUser != "" { - return &authInfo{ - AuthType: AuthTypeKeymasterX509, - IssuedAt: notBefore, - Username: tlsAuthUser, - }, nil - } + var authData authInfo + //if (requiredAuthType & AuthTypeKeymasterX509) != 0 { + tlsAuthUser, notBefore, err := + state.getUsernameIfKeymasterSigned(r.TLS.VerifiedChains) + if err == nil && tlsAuthUser != "" { + state.logger.Debugf(4, "Auth, Is keymastercert") + authData.AuthType = authData.AuthType | AuthTypeKeymasterX509 + authData.IssuedAt = notBefore + authData.Username = tlsAuthUser } if (requiredAuthType & AuthTypeIPCertificate) != 0 { clientName, notBefore, userErr, err := state.getUsernameIfIPRestricted(r.TLS.VerifiedChains, r) - if userErr != nil { - state.writeFailureResponse(w, r, http.StatusForbidden, - fmt.Sprintf("%s", userErr)) - return nil, userErr + // if not keymasterd cert AND not ipcert either then we return + // moe explicit errors + if authData.Username == "" { + state.logger.Printf("after eval, but username is empty") + if userErr != nil { + state.writeFailureResponse(w, r, http.StatusForbidden, + fmt.Sprintf("%s", userErr)) + return nil, userErr + } + if err != nil { + state.writeFailureResponse(w, r, + http.StatusInternalServerError, "") + return nil, err + } } - if err != nil { - state.writeFailureResponse(w, r, - http.StatusInternalServerError, "") - return nil, err + + if err == nil && userErr == nil { + authData.AuthType = authData.AuthType | AuthTypeIPCertificate + authData.IssuedAt = notBefore + authData.Username = clientName } - return &authInfo{ - AuthType: AuthTypeIPCertificate, - IssuedAt: notBefore, - Username: clientName, - }, nil } + if authData.Username != "" { + state.logger.Debugf(4, "returning tls cert authinfo") + return &authData, nil + } + state.logger.Debugf(4, "NOT returning tls cert authinfo authData=%+v", authData) } } // Next we check for cookies diff --git a/cmd/keymasterd/certgen.go b/cmd/keymasterd/certgen.go index 2efab68..007da46 100644 --- a/cmd/keymasterd/certgen.go +++ b/cmd/keymasterd/certgen.go @@ -102,9 +102,9 @@ func (state *RuntimeState) certGenHandler(w http.ResponseWriter, r *http.Request } } // temporary hack - if (authData.AuthType & AuthTypeKeymasterX509) == AuthTypeKeymasterX509 { - sufficientAuthLevel = true - } + //if (authData.AuthType & AuthTypeKeymasterX509) == AuthTypeKeymasterX509 { + // sufficientAuthLevel = true + //} // if you have u2f you can always get the cert if (authData.AuthType & AuthTypeU2F) == AuthTypeU2F { diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index f892a97..e0c26ac 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -131,15 +131,9 @@ func (state *RuntimeState) isAutomationAdmin(user string) bool { func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { var signerIsNull bool //var keySigner crypto.Signer - // copy runtime singer if not nil state.Mutex.Lock() signerIsNull = (state.Signer == nil) - /* - if !signerIsNull { - keySigner = state.Signer - } - */ state.Mutex.Unlock() //local sanity tests From 9e2516c017994fdd291b7d41311c2037a9c34be6 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Wed, 4 Dec 2024 10:20:31 -0800 Subject: [PATCH 09/15] denylist for fingerprints --- cmd/keymasterd/app.go | 10 +++++++++- cmd/keymasterd/config.go | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/keymasterd/app.go b/cmd/keymasterd/app.go index d4b1409..efad734 100644 --- a/cmd/keymasterd/app.go +++ b/cmd/keymasterd/app.go @@ -794,6 +794,15 @@ func (state *RuntimeState) getUsernameIfKeymasterSigned(VerifiedChains [][]*x509 if err != nil { return "", time.Time{}, err } + userPubKeyFP, err := getKeyFingerprint(chain[0].PublicKey) + if err != nil { + return "", time.Time{}, err + } + for _, revokedKeyFP := range state.Config.DenyTrustData.KeyDenyFPsshSha256 { + if userPubKeyFP == revokedKeyFP { + return "", time.Time{}, fmt.Errorf("revoked key with FP:%s", revokedKeyFP) + } + } for _, key := range state.KeymasterPublicKeys { fp, err := getKeyFingerprint(key) if err != nil { @@ -870,7 +879,6 @@ func (state *RuntimeState) checkAuth(w http.ResponseWriter, r *http.Request, req "looks like authtype tls keymaster or ip cert, r.tls=%+v", r.TLS) if len(r.TLS.VerifiedChains) > 0 { var authData authInfo - //if (requiredAuthType & AuthTypeKeymasterX509) != 0 { tlsAuthUser, notBefore, err := state.getUsernameIfKeymasterSigned(r.TLS.VerifiedChains) if err == nil && tlsAuthUser != "" { diff --git a/cmd/keymasterd/config.go b/cmd/keymasterd/config.go index 4fb2891..15809cc 100644 --- a/cmd/keymasterd/config.go +++ b/cmd/keymasterd/config.go @@ -190,6 +190,10 @@ type SymantecVIPConfig struct { RequireAppAproval bool `yaml:"require_app_approval"` } +type DenyKeyConfig struct { + KeyDenyFPsshSha256 []string `yaml:"key_deny_list_ssh_sha256"` +} + type AppConfigFile struct { Base baseConfig AwsCerts awsCertsConfig `yaml:"aws_certs"` @@ -203,6 +207,7 @@ type AppConfigFile struct { OpenIDConnectIDP OpenIDConnectIDPConfig `yaml:"openid_connect_idp"` SymantecVIP SymantecVIPConfig ProfileStorage ProfileStorageConfig + DenyTrustData DenyKeyConfig } const ( From f49451250122dde8eb669f87b8ad12e32427fff9 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Wed, 4 Dec 2024 14:47:13 -0800 Subject: [PATCH 10/15] tests --- cmd/keymasterd/roleRequestingCert.go | 11 +-- cmd/keymasterd/roleRequestingCert_test.go | 85 +++++++++++++++++++++++ 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index e0c26ac..f420561 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -28,7 +28,7 @@ type roleRequestingCertGenParams struct { } func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequestingCertGenParams, error, error) { - state.logger.Debugf(3, "Got client POST connection") + state.logger.Debugf(3, "parseRoleCertGenParams: Got client POST connection") err := r.ParseForm() if err != nil { state.logger.Println(err) @@ -154,7 +154,7 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r // TODO: this should be a different check, for now keep it to admin users if !state.isAutomationAdmin(authData.Username) { - state.writeFailureResponse(w, r, http.StatusUnauthorized, + state.writeFailureResponse(w, r, http.StatusForbidden, "Not an admin user") return } @@ -302,16 +302,9 @@ func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r * func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { var signerIsNull bool - //var keySigner crypto.Signer - // copy runtime singer if not nil state.Mutex.Lock() signerIsNull = (state.Signer == nil) - /* - if !signerIsNull { - keySigner = state.Signer - } - */ state.Mutex.Unlock() //local sanity tests diff --git a/cmd/keymasterd/roleRequestingCert_test.go b/cmd/keymasterd/roleRequestingCert_test.go index fd35066..3b4a4f6 100644 --- a/cmd/keymasterd/roleRequestingCert_test.go +++ b/cmd/keymasterd/roleRequestingCert_test.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "net" "net/http" + "net/http/httptest" "net/url" "os" "strconv" @@ -108,6 +109,90 @@ func TestRoleRequetingCertGenHandler(t *testing.T) { // TODO: check body content is actually pem } +func TestRoleRequetingCertGenHandlerTLSAuth(t *testing.T) { + state, tmpdir, err := testCreateRuntimeStateWithBothCAs(t) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + state.Config.Base.AutomationUsers = append(state.Config.Base.AutomationUsers, "role1") + state.Config.Base.AutomationAdmins = append(state.Config.Base.AutomationAdmins, "admin1") + state.Config.Base.AllowedAuthBackendsForCerts = append(state.Config.Base.AllowedAuthBackendsForCerts, proto.AuthTypeIPCertificate) + + //Bob id not admin, should fail with forbidden + req := httptest.NewRequest("POST", getRoleRequestingPath, nil) + req.TLS, err = testMakeConnectionState("testdata/bob.pem", + "testdata/KeymasterCA.pem") + + _, err = checkRequestHandlerCode(req, state.roleRequetingCertGenHandler, http.StatusForbidden) + if err != nil { + t.Fatal(err) + } + + //alice is admin... but there is no data, it should fail + req = httptest.NewRequest("POST", getRoleRequestingPath, nil) + req.TLS, err = testMakeConnectionState("testdata/alice.pem", + "testdata/KeymasterCA.pem") + _, err = checkRequestHandlerCode(req, state.roleRequetingCertGenHandler, http.StatusBadRequest) + if err != nil { + t.Fatal(err) + } + // lets create valid inputs + userPemBlock, _ := pem.Decode([]byte(testUserPEMPublicKey)) + b64public := base64.RawURLEncoding.EncodeToString(userPemBlock.Bytes) + form := url.Values{} + form.Add("identity", "role1") + form.Add("requestor_netblock", "127.0.0.1/32") + form.Add("pubkey", b64public) + form.Add("target_netblock", "192.168.0.174/32") + + req2, err := http.NewRequest("POST", getRoleRequestingPath, strings.NewReader(form.Encode())) + if err != nil { + t.Fatal(err) + } + req2.Header.Add("Content-Length", strconv.Itoa(len(form.Encode()))) + req2.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req2.TLS, err = testMakeConnectionState("testdata/alice.pem", + "testdata/KeymasterCA.pem") + rr, err := checkRequestHandlerCode(req2, state.roleRequetingCertGenHandler, http.StatusOK) + if err != nil { + t.Fatal(err) + } + // TODO: check body response is actual cert to get a cert + resp := rr.Result() + pemData, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + block, _ := pem.Decode(pemData) + if block.Type != "CERTIFICATE" { + t.Fatalf("no CERTIFICATE found") + } + rrCert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + t.Fatal(err) + } + req3, err := createKeyBodyRequest("POST", "/certgen/role1?type=x509", testUserPEMPublicKey, "") + if err != nil { + t.Fatal(err) + } + req3.RemoteAddr = "127.0.0.1:12345" + var fakePeerCertificates []*x509.Certificate + var fakeVerifiedChains [][]*x509.Certificate + fakePeerCertificates = append(fakePeerCertificates, rrCert) + fakeVerifiedChains = append(fakeVerifiedChains, fakePeerCertificates) + connectionState := &tls.ConnectionState{ + VerifiedChains: fakeVerifiedChains, + PeerCertificates: fakePeerCertificates} + req3.TLS = connectionState + _, err = checkRequestHandlerCode(req3, state.certGenHandler, http.StatusOK) + if err != nil { + t.Fatal(err) + } + // and now use the cert to +} + func TestRefreshRoleRequetingCertGenHandler(t *testing.T) { state, passwdFile, err := setupValidRuntimeStateSigner(t) if err != nil { From 9e3ba3664a18a9ffeea44cc5af3bc37894e9e705 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Wed, 4 Dec 2024 19:27:59 -0800 Subject: [PATCH 11/15] cleanup --- cmd/keymasterd/app.go | 2 +- cmd/keymasterd/certgen.go | 5 ----- cmd/keymasterd/roleRequestingCert.go | 20 +++----------------- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/cmd/keymasterd/app.go b/cmd/keymasterd/app.go index efad734..7e4579c 100644 --- a/cmd/keymasterd/app.go +++ b/cmd/keymasterd/app.go @@ -891,7 +891,7 @@ func (state *RuntimeState) checkAuth(w http.ResponseWriter, r *http.Request, req clientName, notBefore, userErr, err := state.getUsernameIfIPRestricted(r.TLS.VerifiedChains, r) // if not keymasterd cert AND not ipcert either then we return - // moe explicit errors + // more explicit errors if authData.Username == "" { state.logger.Printf("after eval, but username is empty") if userErr != nil { diff --git a/cmd/keymasterd/certgen.go b/cmd/keymasterd/certgen.go index 007da46..f7fa593 100644 --- a/cmd/keymasterd/certgen.go +++ b/cmd/keymasterd/certgen.go @@ -101,11 +101,6 @@ func (state *RuntimeState) certGenHandler(w http.ResponseWriter, r *http.Request sufficientAuthLevel = true } } - // temporary hack - //if (authData.AuthType & AuthTypeKeymasterX509) == AuthTypeKeymasterX509 { - // sufficientAuthLevel = true - //} - // if you have u2f you can always get the cert if (authData.AuthType & AuthTypeU2F) == AuthTypeU2F { sufficientAuthLevel = true diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index f420561..90d1ae9 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -14,8 +14,6 @@ import ( "github.com/Cloud-Foundations/keymaster/lib/util" ) -//const svcPrefixList= string ["svc-","role-"] - const getRoleRequestingPath = "/v1/getRoleRequestingCert" const refreshRoleRequestingCertPath = "/v1/refreshRoleRequestingCert" const maxRoleRequestingCertDuration = time.Hour * 24 * 45 @@ -42,7 +40,7 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest Target (VM) netblock: target_netblock Optional duration: duration (i.e. 730h: :golang: time format) */ - // Role + // Role/Identity roleName := r.Form.Get("identity") if roleName == "" { return nil, fmt.Errorf("Missing identity parameter"), nil @@ -53,7 +51,6 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest } if !ok { return nil, fmt.Errorf("requested role is not automation user"), nil - //return "", time.Time{}, fmt.Errorf("Bad username for ip restricted cert"), nil } rvalue.Role = roleName @@ -84,7 +81,6 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest state.logger.Printf("%s", err) return nil, fmt.Errorf("invalid netblock %s", netBlock), nil } - //rvalue.RequestorNetblocks = append(rvalue.RequestorNetblocks, *parsedNetBlock) } // publickey @@ -125,13 +121,10 @@ func (state *RuntimeState) isAutomationAdmin(user string) bool { } } return false - } func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { var signerIsNull bool - //var keySigner crypto.Signer - // copy runtime singer if not nil state.Mutex.Lock() signerIsNull = (state.Signer == nil) state.Mutex.Unlock() @@ -152,7 +145,7 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r } w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username) - // TODO: this should be a different check, for now keep it to admin users + // TODO: this should be a different check, for now keep it to automationadmin users if !state.isAutomationAdmin(authData.Username) { state.writeFailureResponse(w, r, http.StatusForbidden, "Not an admin user") @@ -223,7 +216,6 @@ func (state *RuntimeState) withParamsGenegneratRoleRequetingCert(params *roleReq } func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r *http.Request) (*roleRequestingCertGenParams, error, error) { - state.logger.Debugf(4, "Got client POST connection") err := r.ParseForm() if err != nil { @@ -241,7 +233,6 @@ func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r * Optional duration: duration (i.e. 730h: :golang: time format) */ // Role - identityName := authData.Username if identityName == "" { return nil, fmt.Errorf("Missing identity parameter"), nil @@ -252,11 +243,11 @@ func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r * } if !ok { return nil, fmt.Errorf("requested role is not automation user"), nil - //return "", time.Time{}, fmt.Errorf("Bad username for ip restricted cert"), nil } rvalue.Role = identityName //Duration + // TODO: actually parse to allow smaller valjues rvalue.Duration = maxRoleRequestingCertDuration // publickey @@ -300,13 +291,10 @@ func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r * } func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { - var signerIsNull bool - state.Mutex.Lock() signerIsNull = (state.Signer == nil) state.Mutex.Unlock() - //local sanity tests if signerIsNull { state.writeFailureResponse(w, r, http.StatusInternalServerError, "") @@ -349,12 +337,10 @@ func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWri return } clientIpAddress := util.GetRequestRealIp(r) - w.Header().Set("Content-Disposition", `attachment; filename="roleRequstingCert.pem"`) w.WriteHeader(200) fmt.Fprintf(w, "%s", pemCert) state.logger.Printf("Generated x509 role Requesting Certificate for %s (from %s). Serial: %s", params.Role, clientIpAddress, cert.SerialNumber.String()) - return } From 028dc0b3526ccf957efb72aba38d61d13bc1471a Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Wed, 4 Dec 2024 19:29:59 -0800 Subject: [PATCH 12/15] actually this is a minor update --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 14ddee5..3b9a2dc 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ endif BINARY=keymaster # These are the values we want to pass for Version and BuildTime -VERSION?=1.15.6 +VERSION?=1.16.0 DEFAULT_HOST?= VERSION_FLAVOUR?= EXTRA_LDFLAGS?= From 76dd21d621c91bb601439a30a471ce82bb905b2d Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Thu, 5 Dec 2024 14:32:01 -0800 Subject: [PATCH 13/15] more negative tests and move from form to postForm --- cmd/keymasterd/roleRequestingCert.go | 8 +++--- cmd/keymasterd/roleRequestingCert_test.go | 33 ++++++++++++++++++++++- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index 90d1ae9..4a24e9c 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -41,7 +41,7 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest Optional duration: duration (i.e. 730h: :golang: time format) */ // Role/Identity - roleName := r.Form.Get("identity") + roleName := r.PostForm.Get("identity") if roleName == "" { return nil, fmt.Errorf("Missing identity parameter"), nil } @@ -58,7 +58,7 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest rvalue.Duration = maxRoleRequestingCertDuration //RequestorNetblocks - requestorNetblockStrings, ok := r.Form["requestor_netblock"] + requestorNetblockStrings, ok := r.PostForm["requestor_netblock"] if !ok { return nil, fmt.Errorf("missing required requestor_netblock param"), nil } @@ -71,7 +71,7 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest rvalue.RequestorNetblocks = append(rvalue.RequestorNetblocks, *parsedNetBlock) } //TargetNetblocks - targetNetblockStrings, ok := r.Form["target_netblock"] + targetNetblockStrings, ok := r.PostForm["target_netblock"] if !ok { return nil, fmt.Errorf("missing required requestor_netblock param"), nil } @@ -84,7 +84,7 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest } // publickey - b64pubkey := r.Form.Get("pubkey") + b64pubkey := r.PostForm.Get("pubkey") if b64pubkey == "" { return nil, fmt.Errorf("Missing pubkey parameter"), nil } diff --git a/cmd/keymasterd/roleRequestingCert_test.go b/cmd/keymasterd/roleRequestingCert_test.go index 3b4a4f6..52c9853 100644 --- a/cmd/keymasterd/roleRequestingCert_test.go +++ b/cmd/keymasterd/roleRequestingCert_test.go @@ -47,7 +47,6 @@ func TestParseRoleCertGenParams(t *testing.T) { if err != nil { t.Fatal(err) } - //req.AddCookie(&authCookie) req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode()))) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") @@ -59,6 +58,22 @@ func TestParseRoleCertGenParams(t *testing.T) { t.Fatal(userErr) } + // now test with broken public key + form.Set("pubkey", "aGVsbG8gdGhpcyBpcyBzb21laGl0bmcK") + req2, err := http.NewRequest("POST", getRoleRequestingPath, strings.NewReader(form.Encode())) + if err != nil { + t.Fatal(err) + } + req2.Header.Add("Content-Length", strconv.Itoa(len(form.Encode()))) + req2.Header.Add("Content-Type", "application/x-www-form-urlencoded") + _, userErr, err = state.parseRoleCertGenParams(req2) + if err != nil { + t.Fatal(err) + } + if userErr == nil { + t.Fatal("should have failed because Public key is not valid") + } + } func TestRoleRequetingCertGenHandler(t *testing.T) { @@ -107,6 +122,22 @@ func TestRoleRequetingCertGenHandler(t *testing.T) { t.Fatal(err) } // TODO: check body content is actually pem + + //now disable the role as automation use and it should fail + state.Config.Base.AutomationUsers = []string{} + req2, err := http.NewRequest("POST", getRoleRequestingPath, strings.NewReader(form.Encode())) + if err != nil { + t.Fatal(err) + } + req2.AddCookie(&authCookie) + req2.Header.Add("Content-Length", strconv.Itoa(len(form.Encode()))) + req2.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + _, err = checkRequestHandlerCode(req, state.roleRequetingCertGenHandler, http.StatusBadRequest) + if err != nil { + t.Fatal(err) + } + } func TestRoleRequetingCertGenHandlerTLSAuth(t *testing.T) { From 987348db8eed60c5e0aa20f17b8f093ce3516033 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Sat, 7 Dec 2024 16:15:56 -0800 Subject: [PATCH 14/15] addressing fix requests --- cmd/keymasterd/app.go | 2 +- cmd/keymasterd/roleRequestingCert.go | 23 ++++++++++++----------- cmd/keymasterd/roleRequestingCert_test.go | 4 ++-- lib/certgen/iprestricted.go | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/cmd/keymasterd/app.go b/cmd/keymasterd/app.go index 7e4579c..ba70234 100644 --- a/cmd/keymasterd/app.go +++ b/cmd/keymasterd/app.go @@ -1956,7 +1956,7 @@ func main() { runtimeState.VerifyAuthTokenHandler) } serviceMux.HandleFunc(getRoleRequestingPath, runtimeState.roleRequetingCertGenHandler) - serviceMux.HandleFunc(refreshRoleRequestingCertPath, runtimeState.refreshRoleRequetingCertGenHandler) + serviceMux.HandleFunc(refreshRoleRequestingCertPath, runtimeState.refreshRoleRequestingCertGenHandler) serviceMux.HandleFunc("/", runtimeState.defaultPathHandler) cfg := &tls.Config{ diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index 4a24e9c..e988c80 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -22,6 +22,7 @@ type roleRequestingCertGenParams struct { Role string Duration time.Duration RequestorNetblocks []net.IPNet + TargetNetblocks []net.IPNet UserPub interface{} } @@ -152,8 +153,8 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r return } - // TODO: maybe add a check to ensure role certs cannot get role certs? - // + // TODO: maybe add a check to ensure no self-replication + // We dont anything to request a rolerequsting role for itself /// Now we parse the inputs if r.Method != "POST" { @@ -170,7 +171,7 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r userError.Error()) return } - pemCert, cert, err := state.withParamsGenegneratRoleRequetingCert(params) + pemCert, cert, err := state.withParamsGenerateRoleRequestingCert(params) if err != nil { state.writeFailureResponse(w, r, http.StatusInternalServerError, "") state.logger.Printf("Error generating cert", err) @@ -187,7 +188,7 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r return } -func (state *RuntimeState) withParamsGenegneratRoleRequetingCert(params *roleRequestingCertGenParams) (string, *x509.Certificate, error) { +func (state *RuntimeState) withParamsGenerateRoleRequestingCert(params *roleRequestingCertGenParams) (string, *x509.Certificate, error) { signer, caCertDer, err := state.getSignerX509CAForPublic(params.UserPub) if err != nil { return "", nil, fmt.Errorf("Error Finding Cert for public key: %s\n data", err) @@ -276,10 +277,10 @@ func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r * // networks if r.TLS == nil { - return nil, fmt.Errorf("MUST only come form certificate"), nil + return nil, fmt.Errorf("MUST only come from certificate"), nil } if len(r.TLS.VerifiedChains) < 1 { - return nil, fmt.Errorf("MUST only come form certificate"), nil + return nil, fmt.Errorf("MUST only come from certificate"), nil } userCert := r.TLS.VerifiedChains[0][0] certNets, err := certgen.ExtractIPNetsFromIPRestrictedX509(userCert) @@ -290,7 +291,7 @@ func (state *RuntimeState) parseRefreshRoleCertGenParams(authData *authInfo, r * return &rvalue, nil, nil } -func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWriter, r *http.Request) { +func (state *RuntimeState) refreshRoleRequestingCertGenHandler(w http.ResponseWriter, r *http.Request) { var signerIsNull bool state.Mutex.Lock() signerIsNull = (state.Signer == nil) @@ -302,7 +303,7 @@ func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWri return } - state.logger.Debugf(1, "refreshRoleRequetingCertGenHandler before auth") + state.logger.Debugf(1, "refreshRoleRequestingCertGenHandler before auth") authData, err := state.checkAuth(w, r, AuthTypeIPCertificate) if err != nil { state.logger.Debugf(1, "%v", err) @@ -310,7 +311,7 @@ func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWri return } // TODO: we need to do denylist checks here against the cert/certkey - state.logger.Debugf(1, "refreshRoleRequetingCertGenHandler: authenticated") + state.logger.Debugf(1, "refreshRoleRequestingCertGenHandler: authenticated") w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username) @@ -325,12 +326,12 @@ func (state *RuntimeState) refreshRoleRequetingCertGenHandler(w http.ResponseWri return } if userError != nil { - state.logger.Debugf(1, "refreshRoleRequetingCertGenHandler: error parsing params err=%s", userError) + state.logger.Debugf(1, "refreshRoleRequestingCertGenHandler: error parsing params err=%s", userError) state.writeFailureResponse(w, r, http.StatusBadRequest, userError.Error()) return } - pemCert, cert, err := state.withParamsGenegneratRoleRequetingCert(params) + pemCert, cert, err := state.withParamsGenerateRoleRequestingCert(params) if err != nil { state.writeFailureResponse(w, r, http.StatusInternalServerError, "") state.logger.Printf("Error generating cert", err) diff --git a/cmd/keymasterd/roleRequestingCert_test.go b/cmd/keymasterd/roleRequestingCert_test.go index 52c9853..3a4250e 100644 --- a/cmd/keymasterd/roleRequestingCert_test.go +++ b/cmd/keymasterd/roleRequestingCert_test.go @@ -257,7 +257,7 @@ func TestRefreshRoleRequetingCertGenHandler(t *testing.T) { RequestorNetblocks: netblockList, UserPub: userPub, } - _, rrcert, err := state.withParamsGenegneratRoleRequetingCert(&initialrrParams) + _, rrcert, err := state.withParamsGenerateRoleRequestingCert(&initialrrParams) if err != nil { t.Fatal(err) } @@ -284,7 +284,7 @@ func TestRefreshRoleRequetingCertGenHandler(t *testing.T) { req.TLS = connectionState //TODO add fail value - _, err = checkRequestHandlerCode(req, state.refreshRoleRequetingCertGenHandler, http.StatusOK) + _, err = checkRequestHandlerCode(req, state.refreshRoleRequestingCertGenHandler, http.StatusOK) if err != nil { t.Fatal(err) } diff --git a/lib/certgen/iprestricted.go b/lib/certgen/iprestricted.go index dc64e9f..d2409c8 100644 --- a/lib/certgen/iprestricted.go +++ b/lib/certgen/iprestricted.go @@ -207,7 +207,7 @@ func ExtractIPNetsFromIPRestrictedX509(userCert *x509.Certificate) ([]net.IPNet, } } if extension == nil { - return nil, fmt.Errorf("externsion not found") + return nil, fmt.Errorf("extension not found") } var ipAddressFamilyList []IpAdressFamily _, err = asn1.Unmarshal(extension.Value, &ipAddressFamilyList) From 97629a5db04a25cbd5061de2748dee7b29cbe3d6 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Mon, 9 Dec 2024 08:13:27 -0800 Subject: [PATCH 15/15] missing stuff --- cmd/keymasterd/roleRequestingCert.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/keymasterd/roleRequestingCert.go b/cmd/keymasterd/roleRequestingCert.go index e988c80..7fee759 100644 --- a/cmd/keymasterd/roleRequestingCert.go +++ b/cmd/keymasterd/roleRequestingCert.go @@ -77,11 +77,12 @@ func (state *RuntimeState) parseRoleCertGenParams(r *http.Request) (*roleRequest return nil, fmt.Errorf("missing required requestor_netblock param"), nil } for _, netBlock := range targetNetblockStrings { - _, _, err := net.ParseCIDR(netBlock) + _, parsedNetBlock, err := net.ParseCIDR(netBlock) if err != nil { state.logger.Printf("%s", err) return nil, fmt.Errorf("invalid netblock %s", netBlock), nil } + rvalue.TargetNetblocks = append(rvalue.TargetNetblocks, *parsedNetBlock) } // publickey @@ -154,7 +155,7 @@ func (state *RuntimeState) roleRequetingCertGenHandler(w http.ResponseWriter, r } // TODO: maybe add a check to ensure no self-replication - // We dont anything to request a rolerequsting role for itself + // We dont anything to request a rolerequesting role for itself /// Now we parse the inputs if r.Method != "POST" {