11//
22// (C) Copyright 2019-2022 Intel Corporation.
3- // (C) Copyright 2025 Hewlett Packard Enterprise Development LP
3+ // (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP
44//
55// SPDX-License-Identifier: BSD-2-Clause-Patent
66//
@@ -12,7 +12,10 @@ import (
1212 "crypto"
1313 "fmt"
1414 "path/filepath"
15+ "time"
1516
17+ "github.com/google/uuid"
18+ "github.com/pkg/errors"
1619 "google.golang.org/protobuf/proto"
1720
1821 "github.com/daos-stack/daos/src/control/drpc"
@@ -84,11 +87,14 @@ func (m *SecurityModule) validateRespWithStatus(status daos.Status) ([]byte, err
8487
8588// HandleCall is the handler for calls to the SecurityModule
8689func (m * SecurityModule ) HandleCall (_ context.Context , session * drpc.Session , method drpc.Method , body []byte ) ([]byte , error ) {
87- if method != daos .MethodValidateCredentials {
90+ switch method {
91+ case daos .MethodValidateCredentials :
92+ return m .processValidateCredentials (body )
93+ case daos .MethodValidateNodeCert :
94+ return m .processValidateNodeCert (body )
95+ default :
8896 return nil , drpc .UnknownMethodFailure ()
8997 }
90-
91- return m .processValidateCredentials (body )
9298}
9399
94100// ID will return Security module ID
@@ -105,7 +111,79 @@ func (m *SecurityModule) GetMethod(id int32) (drpc.Method, error) {
105111 switch id {
106112 case daos .MethodValidateCredentials .ID ():
107113 return daos .MethodValidateCredentials , nil
114+ case daos .MethodValidateNodeCert .ID ():
115+ return daos .MethodValidateNodeCert , nil
108116 default :
109117 return nil , fmt .Errorf ("invalid method ID %d for module %s" , id , m .String ())
110118 }
111119}
120+
121+ func (m * SecurityModule ) processValidateNodeCert (body []byte ) ([]byte , error ) {
122+ req := & auth.ValidateNodeCertReq {}
123+ if err := proto .Unmarshal (body , req ); err != nil {
124+ return nil , drpc .UnmarshalingPayloadFailure ()
125+ }
126+
127+ poolUUID , err := uuid .FromBytes (req .GetPoolUuid ())
128+ if err != nil {
129+ return m .rejectNodeCert (req , daos .InvalidInput ,
130+ fmt .Sprintf ("invalid pool UUID (%d bytes)" , len (req .GetPoolUuid ())))
131+ }
132+
133+ daosCA , err := m .config .CACert ()
134+ if err != nil {
135+ return m .rejectNodeCert (req , daos .NoCert ,
136+ fmt .Sprintf ("failed to load DAOS CA: %v" , err ))
137+ }
138+ if daosCA == nil {
139+ return m .rejectNodeCert (req , daos .NoCert , "no DAOS CA without transport security" )
140+ }
141+
142+ p := & security.NodeCertPresentation {
143+ Root : daosCA ,
144+ PoolCA : req .PoolCa ,
145+ Cert : req .NodeCert ,
146+ PoPSig : req .PopSig ,
147+ PoPPayload : req .PopPayload ,
148+ PoolUUID : poolUUID ,
149+ MachineName : req .MachineName ,
150+ Watermarks : req .CertWatermarks ,
151+ MaxSkew : m .config .CertMaxClockSkew ,
152+ Now : time .Now (),
153+ }
154+ payload , err := p .Validate ()
155+ if err != nil {
156+ return m .rejectNodeCert (req , validationStatus (err ), err .Error ())
157+ }
158+
159+ m .log .Debugf ("node cert validated: pool=%s, handle=%s" , poolUUID , payload .HandleID ())
160+
161+ return drpc .Marshal (& auth.ValidateNodeCertResp {Status : 0 })
162+ }
163+
164+ // validationStatus maps the security package's sentinel errors to wire statuses.
165+ func validationStatus (err error ) daos.Status {
166+ switch {
167+ case errors .Is (err , security .ErrInvalidInput ):
168+ return daos .InvalidInput
169+ case errors .Is (err , security .ErrCertInvalid ), errors .Is (err , security .ErrCertNotYetValid ),
170+ errors .Is (err , security .ErrCertRevoked ):
171+ return daos .BadCert
172+ case errors .Is (err , security .ErrPoPInvalid ), errors .Is (err , security .ErrPoPStale ):
173+ return daos .NoPermission
174+ case errors .Is (err , security .ErrBadWatermarks ):
175+ return daos .IOError
176+ default :
177+ return daos .MiscError
178+ }
179+ }
180+
181+ // rejectNodeCert logs and returns a ValidateNodeCertResp carrying status + detail.
182+ func (m * SecurityModule ) rejectNodeCert (req * auth.ValidateNodeCertReq , status daos.Status , detail string ) ([]byte , error ) {
183+ m .log .Errorf ("node cert rejected (pool=%x, status=%s): %s" ,
184+ req .GetPoolUuid (), status , detail )
185+ return drpc .Marshal (& auth.ValidateNodeCertResp {
186+ Status : int32 (status ),
187+ Detail : detail ,
188+ })
189+ }
0 commit comments