Validate ensures the document was signed by an AWS public key. Regions that aren't provided in certificates will use defaults.
(signature, document string, certificates Certificates)
| 51 | // Validate ensures the document was signed by an AWS public key. |
| 52 | // Regions that aren't provided in certificates will use defaults. |
| 53 | func Validate(signature, document string, certificates Certificates) (Identity, error) { |
| 54 | if certificates == nil { |
| 55 | certificates = Certificates{} |
| 56 | } |
| 57 | for _, region := range All { |
| 58 | if _, ok := certificates[region]; ok { |
| 59 | continue |
| 60 | } |
| 61 | defaultCertificate, exists := defaultCertificates[region] |
| 62 | if !exists { |
| 63 | panic("dev error: no certificate exists for region " + region) |
| 64 | } |
| 65 | certificates[region] = defaultCertificate |
| 66 | } |
| 67 | |
| 68 | var instanceIdentity awsInstanceIdentityDocument |
| 69 | err := json.Unmarshal([]byte(document), &instanceIdentity) |
| 70 | if err != nil { |
| 71 | return Identity{}, xerrors.Errorf("parse document: %w", err) |
| 72 | } |
| 73 | rawSignature, err := base64.StdEncoding.DecodeString(signature) |
| 74 | if err != nil { |
| 75 | return Identity{}, xerrors.Errorf("decode signature: %w", err) |
| 76 | } |
| 77 | hashedDocument := sha256.Sum256([]byte(document)) |
| 78 | |
| 79 | for region, certificate := range certificates { |
| 80 | regionBlock, rest := pem.Decode([]byte(certificate)) |
| 81 | if len(rest) != 0 { |
| 82 | return Identity{}, xerrors.Errorf("invalid certificate for %q. %d bytes remain", region, len(rest)) |
| 83 | } |
| 84 | regionCert, err := x509.ParseCertificate(regionBlock.Bytes) |
| 85 | if err != nil { |
| 86 | return Identity{}, xerrors.Errorf("parse certificate: %w", err) |
| 87 | } |
| 88 | regionPublicKey, valid := regionCert.PublicKey.(*rsa.PublicKey) |
| 89 | if !valid { |
| 90 | return Identity{}, xerrors.Errorf("certificate for %q was not an rsa key", region) |
| 91 | } |
| 92 | err = rsa.VerifyPKCS1v15(regionPublicKey, crypto.SHA256, hashedDocument[:], rawSignature) |
| 93 | if err != nil { |
| 94 | continue |
| 95 | } |
| 96 | return Identity{ |
| 97 | InstanceID: instanceIdentity.InstanceID, |
| 98 | Region: region, |
| 99 | }, nil |
| 100 | } |
| 101 | return Identity{}, rsa.ErrVerification |
| 102 | } |
| 103 | |
| 104 | // Default AWS certificates for regions. |
| 105 | // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/verify-signature.html |