Validate ensures the signature was signed by an Azure certificate. It returns the associated VM ID if successful. Verification has two parts, both handled by VerifyWithChainAtTime: 1. PKCS7 signature check: proves the content was signed by the private key corresponding to the certificate in the env
(ctx context.Context, signature string, options Options)
| 211 | // 2. Certificate chain check: proves the signing certificate |
| 212 | // chains to a trusted root through known intermediates. |
| 213 | func Validate(ctx context.Context, signature string, options Options) (string, error) { |
| 214 | data, err := base64.StdEncoding.DecodeString(signature) |
| 215 | if err != nil { |
| 216 | return "", xerrors.Errorf("decode base64: %w", err) |
| 217 | } |
| 218 | pkcs7Mutex.Lock() |
| 219 | pkcs7Data, err := pkcs7.Parse(data) |
| 220 | pkcs7Mutex.Unlock() |
| 221 | if err != nil { |
| 222 | return "", xerrors.Errorf("parse pkcs7: %w", err) |
| 223 | } |
| 224 | signer := pkcs7Data.GetOnlySigner() |
| 225 | if signer == nil { |
| 226 | return "", xerrors.New("no signers for signature") |
| 227 | } |
| 228 | if !allowedSigners.MatchString(signer.Subject.CommonName) { |
| 229 | return "", xerrors.Errorf("unmatched common name of signer: %q", signer.Subject.CommonName) |
| 230 | } |
| 231 | // Azure PKCS7 envelopes typically contain only the signing |
| 232 | // certificate. Inject intermediate certificates so the |
| 233 | // library can build a chain from signer to trusted root. |
| 234 | intermediates := options.Intermediates |
| 235 | if intermediates == nil { |
| 236 | intermediates, err = ParseCertificates() |
| 237 | if err != nil { |
| 238 | return "", xerrors.Errorf("parse hardcoded certificates: %w", err) |
| 239 | } |
| 240 | } |
| 241 | pkcs7Data.Certificates = append(pkcs7Data.Certificates, intermediates...) |
| 242 | // Resolve root trust store. VerifyWithChainAtTime skips |
| 243 | // chain verification when the trust store is nil, so we |
| 244 | // must always provide one. |
| 245 | roots := options.Roots |
| 246 | if roots == nil { |
| 247 | roots, err = rootCertPool() |
| 248 | if err != nil { |
| 249 | return "", xerrors.Errorf("load roots: %w", err) |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | currentTime := options.CurrentTime |
| 254 | if currentTime.IsZero() { |
| 255 | currentTime = time.Now() |
| 256 | } |
| 257 | |
| 258 | // VerifyWithChainAtTime validates both the PKCS7 signature |
| 259 | // (proving the content was signed by the certificate's |
| 260 | // private key) and the certificate chain (proving the signer |
| 261 | // chains to a trusted root). |
| 262 | err = pkcs7Data.VerifyWithChainAtTime(roots, currentTime) |
| 263 | if err != nil { |
| 264 | if options.Offline { |
| 265 | return "", xerrors.Errorf("verify pkcs7: %w", err) |
| 266 | } |
| 267 | |
| 268 | // The chain verification may fail when the signing |
| 269 | // certificate was issued by an intermediate not yet in |
| 270 | // our hardcoded list. Fetch the issuing certificates |