/// <summary>
        /// Resets the policy for the specified <see cref="AttestationType"/> to the default value.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be reset.</param>
        /// <param name="signingKey">If provided, specifies the signing key and certificate used to sign the request to the attestation service.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// If the <paramref name="signingKey"/> parameter is not provided, then the policy document sent to the
        /// attestation service will be unsigned. Unsigned attestation policies are only allowed when the attestation instance is running in AAD mode - if the
        /// attestation instance is running in Isolated mode, then a signing key and signing certificate MUST be provided to ensure that the caller of the API is authorized to change policy.
        /// The <see cref="TokenSigningKey.Certificate"/> fieldMUST be one of the certificates returned by the <see cref="GetPolicyManagementCertificates(CancellationToken)"/> API.
        /// <para/>
        /// </remarks>
        ///
        public virtual AttestationResponse <PolicyResult> ResetPolicy(
            AttestationType attestationType,
            TokenSigningKey signingKey          = default,
            CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(ResetPolicy)}");
            scope.Start();
            try
            {
                AttestationToken tokenToSet = new AttestationToken(null, signingKey);

                var result = _policyClient.Reset(attestationType, tokenToSet.ToString(), cancellationToken);
                var token  = new AttestationToken(result.Value.Token);
                if (_options.TokenOptions.ValidateToken)
                {
                    token.ValidateToken(_options.TokenOptions, GetSigners(cancellationToken), cancellationToken);
                }
                return(new AttestationResponse <PolicyResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Removes one of the attestation policy management certificates.
        /// </summary>
        /// <param name="certificateToRemove">The certificate to remove.</param>
        /// <param name="existingSigningKey">An existing key corresponding to the existing certificate.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
        public virtual async Task <AttestationResponse <PolicyCertificatesModificationResult> > RemovePolicyManagementCertificateAsync(
            X509Certificate2 certificateToRemove,
            AttestationTokenSigningKey existingSigningKey,
            CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(RemovePolicyManagementCertificate)}");
            scope.Start();
            try
            {
                var tokenToRemove = new AttestationToken(
                    BinaryData.FromObjectAsJson(new PolicyCertificateModification(certificateToRemove)),
                    existingSigningKey);

                var result = await _policyManagementClient.RemoveAsync(tokenToRemove.Serialize(), cancellationToken).ConfigureAwait(false);

                var token = AttestationToken.Deserialize(result.Value.Token, _clientDiagnostics);
                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = await GetSignersAsync(true, cancellationToken).ConfigureAwait(false);

                    if (!await token.ValidateTokenAsync(_options.TokenOptions, signers, cancellationToken).ConfigureAwait(false))
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, token);
                    }
                }
                return(new AttestationResponse <PolicyCertificatesModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
        internal async Task <bool> RaiseValidationCallbackAsync(AttestationToken token, AttestationSigner signer, ClientDiagnostics diagnostics, bool isRunningSynchronously, CancellationToken cancellationToken)
        {
            if (diagnostics != null)
            {
                var eventArgs = new AttestationTokenValidationEventArgs(token: token,
                                                                        signer: signer,
                                                                        isRunningSynchronously: isRunningSynchronously,
                                                                        cancellationToken);

                await TokenValidated.RaiseAsync(eventArgs,
                                                nameof(AttestationTokenValidationOptions),
                                                nameof(TokenValidated),
                                                diagnostics).ConfigureAwait(false);

                return(eventArgs.IsValid);
            }
            else
            {
                // If anyone has subscribed to the invocation event, let them know that this didn't work :(.
                if (TokenValidated?.GetInvocationList() != null)
                {
                    throw new Exception("Unable to call validation callback outside of an attestation client operation.");
                }
            }
            return(true);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Retrieves the attesttion policy for the specified <see cref="AttestationType"/>.
        /// </summary>
        /// <param name="attestationType">Attestation Type to retrive.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{String}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// This API returns the underlying attestation policy object stored in the attestation service for this <paramref name="attestationType"/>.
        ///
        /// The actual service response to the API is an RFC 7519 JSON Web Token. This token can be retrieved from <see cref="AttestationResponse{T}.Token"/>.
        /// For the GetPolicyAsync API, the body of the <see cref="AttestationResponse{T}.Token"/> is a <see cref="StoredAttestationPolicy"/> object, NOT a string.
        /// </remarks>
        public virtual async Task <AttestationResponse <string> > GetPolicyAsync(AttestationType attestationType, CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(GetPolicy)}");
            scope.Start();
            try
            {
                var result = await _policyClient.GetAsync(attestationType, cancellationToken).ConfigureAwait(false);

                var token = new AttestationToken(result.Value.Token);
                if (_options.ValidateAttestationTokens)
                {
                    token.ValidateToken(GetSigners(), _options.ValidationCallback);
                }
                using var document = JsonDocument.Parse(token.TokenBody);
                PolicyResult policyResult = PolicyResult.DeserializePolicyResult(document.RootElement);
                var          response     = new AttestationResponse <StoredAttestationPolicy>(result.GetRawResponse(), policyResult.PolicyToken);

                return(new AttestationResponse <string>(result.GetRawResponse(), policyResult.PolicyToken, response.Value.AttestationPolicy));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Adds the specified new signing certificate to the set of policy management certificates.
        /// </summary>
        /// <param name="newSigningCertificate">The new certificate to add.</param>
        /// <param name="existingSigningKey">An existing key corresponding to the existing certificate.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// </remarks>
        public virtual AttestationResponse <PolicyCertificatesModificationResult> AddPolicyManagementCertificate(
            X509Certificate2 newSigningCertificate,
            AttestationTokenSigningKey existingSigningKey,
            CancellationToken cancellationToken = default)
        {
            Argument.AssertNotNull(existingSigningKey, nameof(existingSigningKey));
            Argument.AssertNotNull(newSigningCertificate, nameof(newSigningCertificate));

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(AddPolicyManagementCertificate)}");
            scope.Start();
            try
            {
                var tokenToAdd = new AttestationToken(
                    BinaryData.FromObjectAsJson(new PolicyCertificateModification(newSigningCertificate)),
                    existingSigningKey);
                var result = _policyManagementClient.Add(tokenToAdd.Serialize(), cancellationToken);
                var token  = AttestationToken.Deserialize(result.Value.Token, _clientDiagnostics);
                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = GetSignersAsync(false, cancellationToken).EnsureCompleted();
                    if (!token.ValidateTokenInternal(_options.TokenOptions, signers, false, cancellationToken).EnsureCompleted())
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, token);
                    }
                }
                return(new AttestationResponse <PolicyCertificatesModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Resets the policy for the specified <see cref="AttestationType"/> to the default value.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be reset.</param>
        /// <param name="signingKey">If provided, specifies the signing key used to sign the request to the attestation service.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// If the <paramref name="signingKey"/> parameter is not provided, then the policy document sent to the
        /// attestation service will be unsigned. Unsigned attestation policies are only allowed when the attestation instance is running in AAD mode - if the
        /// attestation instance is running in Isolated mode, then a signing key and signing certificate MUST be provided to ensure that the caller of the API is authorized to change policy.
        /// The <see cref="AttestationTokenSigningKey.Certificate"/> parameter MUST be one of the certificates returned by the <see cref="GetPolicyManagementCertificates(CancellationToken)"/> API.
        /// <para/>
        /// </remarks>
        public virtual async Task <AttestationResponse <PolicyModificationResult> > ResetPolicyAsync(
            AttestationType attestationType,
            AttestationTokenSigningKey signingKey = default,
            CancellationToken cancellationToken   = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(ResetPolicy)}");
            scope.Start();
            try
            {
                AttestationToken tokenToSet = new AttestationToken(null, signingKey);

                var result = await _policyClient.ResetAsync(attestationType, tokenToSet.Serialize(), cancellationToken).ConfigureAwait(false);

                var token = AttestationToken.Deserialize(result.Value.Token, _clientDiagnostics);
                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = await GetSignersAsync(true, cancellationToken).ConfigureAwait(false);

                    if (!await token.ValidateTokenAsync(_options.TokenOptions, signers, cancellationToken).ConfigureAwait(false))
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, token);
                    }
                }
                return(new AttestationResponse <PolicyModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Resets the policy for the specified <see cref="AttestationType"/> to the default value.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be reset.</param>
        /// <param name="authorizationToken">Signed JSON Web Token signed by one of the policy management certificates used to verify the caller is authorized to reset policy to the default value..</param>
        /// <param name="cancellationToken"></param>
        /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
        public virtual async Task <AttestationResponse <PolicyResult> > ResetPolicyAsync(AttestationType attestationType, AttestationToken authorizationToken = default, CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(ResetPolicy)}");
            scope.Start();
            try
            {
                if (authorizationToken == null)
                {
                    authorizationToken = new UnsecuredAttestationToken();
                }
                var result = await _policyClient.ResetAsync(attestationType, authorizationToken.ToString(), cancellationToken).ConfigureAwait(false);

                var token = new AttestationToken(result.Value.Token);
                if (_options.ValidateAttestationTokens)
                {
                    token.ValidateToken(GetSigners(), _options.ValidationCallback);
                }
                return(new AttestationResponse <PolicyResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Sets the attesttion policy for the specified <see cref="AttestationType"/>.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be set.</param>
        /// <param name="policyToSet">Specifies the attestation policy to set.</param>
        /// <param name="signingKey">If provided, specifies the signing key used to sign the request to the attestation service.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// If the <paramref name="signingKey"/> parameter is not provided, then the policy document sent to the
        /// attestation service will be unsigned. Unsigned attestation policies are only allowed when the attestation instance is running in AAD mode - if the
        /// attestation instance is running in Isolated mode, then a signing key and signing certificate MUST be provided to ensure that the caller of the API is authorized to change policy.
        /// The <see cref="AttestationTokenSigningKey.Certificate"/> field MUST be one of the certificates returned by the <see cref="GetPolicyManagementCertificates(CancellationToken)"/> API.
        /// <para/>
        /// Clients need to be able to verify that the attestation policy document was not modified before the policy document was received by the attestation service's enclave.
        /// There are two properties provided in the [PolicyResult][attestation_policy_result] that can be used to verify that the service received the policy document:
        /// <list type="bullet">
        /// <item>
        /// <description><see cref="PolicyModificationResult.PolicySigner"/> - if the <see cref="SetPolicy(AttestationType, string, AttestationTokenSigningKey, CancellationToken)"/> call included a signing certificate, this will be the certificate provided at the time of the `SetPolicy` call. If no policy signer was set, this will be null. </description>
        /// </item>
        /// <item>
        /// <description><see cref="PolicyModificationResult.PolicyTokenHash"/> - this is the hash of the [JSON Web Token][json_web_token] sent to the service</description>
        /// </item>
        /// </list>
        /// To verify the hash, clients can generate an attestation token and verify the hash generated from that token:
        /// <code snippet="Snippet:VerifySigningHash">
        /// // The SetPolicyAsync API will create an AttestationToken signed with the TokenSigningKey to transmit the policy.
        /// // To verify that the policy specified by the caller was received by the service inside the enclave, we
        /// // verify that the hash of the policy document returned from the Attestation Service matches the hash
        /// // of an attestation token created locally.
        /// TokenSigningKey signingKey = new TokenSigningKey(&lt;Customer provided signing key&gt;, &lt;Customer provided certificate&gt;)
        /// var policySetToken = new AttestationToken(
        ///     BinaryData.FromObjectAsJson(new StoredAttestationPolicy { AttestationPolicy = attestationPolicy }),
        ///     signingKey);
        ///
        /// using var shaHasher = SHA256Managed.Create();
        /// byte[] attestationPolicyHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.Serialize()));
        ///
        /// Debug.Assert(attestationPolicyHash.SequenceEqual(setResult.Value.PolicyTokenHash.ToArray()));
        /// </code>
        ///
        /// If the signing key and certificate are not provided, then the SetPolicyAsync API will create an unsecured attestation token
        /// wrapping the attestation policy. To validate the <see cref="PolicyModificationResult.PolicyTokenHash"/> return value, a developer
        /// can create their own <see cref="AttestationToken"/> and create the hash of that.
        /// <code>
        /// using var shaHasher = SHA256Managed.Create();
        /// var policySetToken = new UnsecuredAttestationToken(new StoredAttestationPolicy { AttestationPolicy = disallowDebugging });
        /// disallowDebuggingHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.Serialize()));
        /// </code>
        /// </remarks>
        public virtual AttestationResponse <PolicyModificationResult> SetPolicy(
            AttestationType attestationType,
            string policyToSet,
            AttestationTokenSigningKey signingKey = default,
            CancellationToken cancellationToken   = default)
        {
            Argument.AssertNotNullOrWhiteSpace(policyToSet, nameof(policyToSet));

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(SetPolicy)}");
            scope.Start();
            try
            {
                AttestationToken tokenToSet = new AttestationToken(
                    BinaryData.FromObjectAsJson(new StoredAttestationPolicy {
                    AttestationPolicy = policyToSet,
                }),
                    signingKey);
                var result = _policyClient.Set(attestationType, tokenToSet.Serialize(), cancellationToken);
                var token  = AttestationToken.Deserialize(result.Value.Token);
                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = GetSignersAsync(false, cancellationToken).EnsureCompleted();
                    if (!token.ValidateToken(_options.TokenOptions, signers, cancellationToken))
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, token);
                    }
                }
                return(new AttestationResponse <PolicyModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Removes one of the attestation policy management certificates.
        /// </summary>
        /// <param name="certificateToRemove">The certificate to remove.</param>
        /// <param name="existingSigningKey">An existing key corresponding to the existing certificate.</param>
        /// <param name="existingSigningCertificate">One of the existing policy management certificates.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
        public virtual async Task <AttestationResponse <PolicyCertificatesModificationResult> > RemovePolicyManagementCertificateAsync(
            X509Certificate2 certificateToRemove,
            AsymmetricAlgorithm existingSigningKey,
            X509Certificate2 existingSigningCertificate,
            CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(RemovePolicyManagementCertificate)}");
            scope.Start();
            try
            {
                var tokenToRemove = new SecuredAttestationToken(
                    new PolicyCertificateModification(certificateToRemove),
                    existingSigningKey,
                    existingSigningCertificate);

                var result = await _policyManagementClient.RemoveAsync(tokenToRemove.ToString(), cancellationToken).ConfigureAwait(false);

                var token = new AttestationToken(result.Value.Token);
                if (_options.ValidateAttestationTokens)
                {
                    token.ValidateToken(GetSigners(), _options.ValidationCallback);
                }
                return(new AttestationResponse <PolicyCertificatesModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
        /// <summary>
        /// Retrieves the attesttion policy for the specified <see cref="AttestationType"/>.
        /// </summary>
        /// <param name="certificateToRemove">The certificate to remove.</param>
        /// <param name="existingSigningKey">An existing key corresponding to the existing certificate.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
        public virtual AttestationResponse <PolicyCertificatesModificationResult> RemovePolicyManagementCertificate(
            X509Certificate2 certificateToRemove,
            TokenSigningKey existingSigningKey,
            CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(RemovePolicyManagementCertificate)}");
            scope.Start();
            try
            {
                var tokenToRemove = new AttestationToken(
                    new PolicyCertificateModification(certificateToRemove),
                    existingSigningKey);

                var result = _policyManagementClient.Remove(tokenToRemove.ToString(), cancellationToken);
                var token  = new AttestationToken(result.Value.Token);
                if (_options.TokenOptions.ValidateToken)
                {
                    token.ValidateToken(_options.TokenOptions, GetSigners(cancellationToken), cancellationToken);
                }
                return(new AttestationResponse <PolicyCertificatesModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
        /// <summary>
        /// Adds the specified new signing certificate to the set of policy management certificates.
        /// </summary>
        /// <param name="newSigningCertificate">The new certificate to add.</param>
        /// <param name="existingSigningKey">An existing key corresponding to the existing certificate.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
        public virtual async Task <AttestationResponse <PolicyCertificatesModificationResult> > AddPolicyManagementCertificateAsync(
            X509Certificate2 newSigningCertificate,
            TokenSigningKey existingSigningKey,
            CancellationToken cancellationToken = default)
        {
            Argument.AssertNotNull(existingSigningKey, nameof(existingSigningKey));
            Argument.AssertNotNull(newSigningCertificate, nameof(newSigningCertificate));

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(AddPolicyManagementCertificate)}");
            scope.Start();
            try
            {
                var tokenToAdd = new AttestationToken(
                    new PolicyCertificateModification(newSigningCertificate),
                    existingSigningKey);
                var result = await _policyManagementClient.AddAsync(tokenToAdd.ToString(), cancellationToken).ConfigureAwait(false);

                var token = new AttestationToken(result.Value.Token);
                if (_options.TokenOptions.ValidateToken)
                {
                    await token.ValidateTokenAsync(_options.TokenOptions, await GetSignersAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
                }
                return(new AttestationResponse <PolicyCertificatesModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
        /// <summary>
        /// Sets the attesttion policy for the specified <see cref="AttestationType"/>.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be set.</param>
        /// <param name="policyToSet">Specifies the attestation policy to set.</param>
        /// <param name="signingKey">If provided, specifies the signing key used to sign the request to the attestation service.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// If the <paramref name="signingKey"/> parameter is not provided, then the policy document sent to the
        /// attestation service will be unsigned. Unsigned attestation policies are only allowed when the attestation instance is running in AAD mode - if the
        /// attestation instance is running in Isolated mode, then a signing key and signing certificate MUST be provided to ensure that the caller of the API is authorized to change policy.
        /// The <see cref="TokenSigningKey.Certificate"/> field MUST be one of the certificates returned by the <see cref="GetPolicyManagementCertificates(CancellationToken)"/> API.
        /// <para/>
        /// Clients need to be able to verify that the attestation policy document was not modified before the policy document was received by the attestation service's enclave.
        /// There are two properties provided in the [PolicyResult][attestation_policy_result] that can be used to verify that the service received the policy document:
        /// <list type="bullet">
        /// <item>
        /// <description><see cref="PolicyResult.PolicySigner"/> - if the <see cref="SetPolicy(AttestationType, string, TokenSigningKey, CancellationToken)"/> call included a signing certificate, this will be the certificate provided at the time of the `SetPolicy` call. If no policy signer was set, this will be null. </description>
        /// </item>
        /// <item>
        /// <description><see cref="PolicyResult.PolicyTokenHash"/> - this is the hash of the [JSON Web Token][json_web_token] sent to the service</description>
        /// </item>
        /// </list>
        /// To verify the hash, clients can generate an attestation token and verify the hash generated from that token:
        /// <code snippet="Snippet:VerifySigningHash">
        /// // The SetPolicyAsync API will create an AttestationToken signed with the TokenSigningKey to transmit the policy.
        /// // To verify that the policy specified by the caller was received by the service inside the enclave, we
        /// // verify that the hash of the policy document returned from the Attestation Service matches the hash
        /// // of an attestation token created locally.
        /// TokenSigningKey signingKey = new TokenSigningKey(&lt;Customer provided signing key&gt;, &lt;Customer provided certificate&gt;)
        /// var policySetToken = new AttestationToken(
        ///     new StoredAttestationPolicy { AttestationPolicy = attestationPolicy },
        ///     signingKey);
        ///
        /// using var shaHasher = SHA256Managed.Create();
        /// var attestationPolicyHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.ToString()));
        ///
        /// Debug.Assert(attestationPolicyHash.SequenceEqual(setResult.Value.PolicyTokenHash));
        /// </code>
        ///
        /// If the signing key and certificate are not provided, then the SetPolicyAsync API will create an unsecured attestation token
        /// wrapping the attestation policy. To validate the <see cref="PolicyResult.PolicyTokenHash"/> return value, a developer
        /// can create their own <see cref="AttestationToken"/> and create the hash of that.
        /// <code>
        /// using var shaHasher = SHA256Managed.Create();
        /// var policySetToken = new AttestationToken(new StoredAttestationPolicy { AttestationPolicy = disallowDebugging });
        /// disallowDebuggingHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.ToString()));
        /// </code>
        /// </remarks>
        public virtual async Task <AttestationResponse <PolicyResult> > SetPolicyAsync(
            AttestationType attestationType,
            string policyToSet,
            TokenSigningKey signingKey          = default,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrEmpty(policyToSet))
            {
                throw new ArgumentException($"'{nameof(policyToSet)}' cannot be null or empty.", nameof(policyToSet));
            }

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(SetPolicy)}");
            scope.Start();
            try
            {
                AttestationToken tokenToSet = new AttestationToken(new StoredAttestationPolicy {
                    AttestationPolicy = policyToSet,
                }, signingKey);

                var result = await _policyClient.SetAsync(attestationType, tokenToSet.ToString(), cancellationToken).ConfigureAwait(false);

                var token = new AttestationToken(result.Value.Token);
                if (_options.TokenOptions.ValidateToken)
                {
                    await token.ValidateTokenAsync(_options.TokenOptions, await GetSignersAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
                }
                return(new AttestationResponse <PolicyResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
 internal static void ThrowFailure(IReadOnlyList <AttestationSigner> signers, AttestationToken token)
 {
     throw new AttestationTokenValidationFailedException($"An Attestation Token was rejected by an {nameof(AttestationTokenValidationOptions)}.{nameof(AttestationTokenValidationOptions.TokenValidated)} event handler.")
           {
               Signers = signers,
               Token   = token,
           };
 }
Exemplo n.º 14
0
        /// <summary>
        /// Attest an Open Enclave enclave.
        /// </summary>
        /// <param name="request">Aggregate type containing the information needed to perform an attestation operation.</param>
        /// <param name="async">true if the API call should be asynchronous, false otherwise.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel the request.</param>
        /// <returns>An <see cref="AttestationResponse{AttestationResult}"/> which contains the validated claims for the supplied <paramref name="request"/>.</returns>
        /// <remarks>The <see cref="AttestationRequest.Evidence"/> must be an OpenEnclave Report or OpenEnclave Evidence.</remarks>
        /// <seealso href="https://github.com/openenclave/openenclave"/>  for more information.
        private async Task <AttestationResponse <AttestationResult> > AttestOpenEnclaveInternalAsync(AttestationRequest request, bool async, CancellationToken cancellationToken = default)
        {
            Argument.AssertNotNull(request, nameof(request));
            Argument.AssertNotNull(request.Evidence, nameof(request.Evidence));

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationClient)}.{nameof(AttestOpenEnclave)}");
            scope.Start();
            try
            {
                var attestOpenEnclaveRequest = new AttestOpenEnclaveRequest
                {
                    Report = request.Evidence.ToArray(),
                    DraftPolicyForAttestation = request.DraftPolicyForAttestation,
                    RuntimeData  = null,
                    InitTimeData = null,
                };

                if (request.InittimeData != null)
                {
                    attestOpenEnclaveRequest.InitTimeData = new InitTimeData
                    {
                        Data     = request.InittimeData.BinaryData.ToArray(),
                        DataType = request.InittimeData.DataIsJson ? DataType.Json : DataType.Binary,
                    };
                }

                if (request.RuntimeData != null)
                {
                    attestOpenEnclaveRequest.RuntimeData = new RuntimeData
                    {
                        Data     = request.RuntimeData.BinaryData.ToArray(),
                        DataType = request.RuntimeData.DataIsJson ? DataType.Json : DataType.Binary,
                    };
                }

                var response = async ? await _restClient.AttestOpenEnclaveAsync(attestOpenEnclaveRequest, cancellationToken).ConfigureAwait(false)
                                    : _restClient.AttestOpenEnclave(attestOpenEnclaveRequest, cancellationToken);

                var attestationToken = AttestationToken.Deserialize(response.Value.Token, _clientDiagnostics);

                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = await GetSignersAsync(async, cancellationToken).ConfigureAwait(false);

                    if (!await attestationToken.ValidateTokenInternal(_options.TokenOptions, signers, async, cancellationToken).ConfigureAwait(false))
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, attestationToken);
                    }
                }

                return(new AttestationResponse <AttestationResult>(response.GetRawResponse(), attestationToken));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Sets the attesttion policy for the specified <see cref="AttestationType"/>.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be set.</param>
        /// <param name="policyToSet">Specifies the attestation policy to set.</param>
        /// <param name="signingKey">If provided, specifies the signing key used to sign the request to the attestation service.</param>
        /// <param name="signingCertificate">If provided, specifies the X.509 certificate which will be used to validate the request with the attestation service.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// The <paramref name="signingKey"/> and <paramref name="signingCertificate"/> parameters are optional, but if one is provided the other must also be provided.
        /// <para/>
        /// If the <paramref name="signingKey"/> and <paramref name="signingCertificate"/> parameters are not provided, then the policy document sent to the
        /// attestation service will be unsigned. Unsigned attestation policies are only allowed when the attestation instance is running in AAD mode - if the
        /// attestation instance is running in Isolated mode, then a signing key and signing certificate MUST be provided to ensure that the caller of the API is authorized to change policy.
        /// The <paramref name="signingCertificate"/> parameter MUST be one of the certificates returned by the <see cref="GetPolicyManagementCertificates(CancellationToken)"/> API.
        /// <para/>
        /// <para/>
        /// Clients need to be able to verify that the attestation policy document was not modified before the policy document was received by the attestation service's enclave.
        /// There are two properties provided in the [PolicyResult][attestation_policy_result] that can be used to verify that the service received the policy document:
        /// <list type="bullet">
        /// <item>
        /// <description><see cref="PolicyResult.PolicySigner"/> - if the <see cref="SetPolicy(AttestationType, string, AsymmetricAlgorithm, X509Certificate2, CancellationToken)"/> call included a signing certificate, this will be the certificate provided at the time of the `SetPolicy` call. If no policy signer was set, this will be null. </description>
        /// </item>
        /// <item>
        /// <description><see cref="PolicyResult.PolicyTokenHash"/> - this is the hash of the [JSON Web Token][json_web_token] sent to the service</description>
        /// </item>
        /// </list>
        /// To verify the hash, clients can generate an attestation token and verify the hash generated from that token:
        /// <code snippet="Snippet:VerifySigningHash">
        /// // The SetPolicyAsync API will create a SecuredAttestationToken to transmit the policy.
        /// var policySetToken = new SecuredAttestationToken(new StoredAttestationPolicy { AttestationPolicy = attestationPolicy }, TestEnvironment.PolicySigningKey0, policyTokenSigner);
        ///
        /// var shaHasher = SHA256Managed.Create();
        /// var attestationPolicyHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.ToString()));
        ///
        /// CollectionAssert.AreEqual(attestationPolicyHash, setResult.Value.PolicyTokenHash);
        /// </code>
        ///
        /// If the signing key and certificate are not provided, then the SetPolicyAsync API will create an unsecured attestation token
        /// wrapping the attestation policy. To validate the <see cref="PolicyResult.PolicyTokenHash"/> return value, a developer
        /// can create their own <see cref="UnsecuredAttestationToken"/> and create the hash of that.
        /// <code>
        /// var shaHasher = SHA256Managed.Create();
        /// var policySetToken = new UnsecuredAttestationToken(new StoredAttestationPolicy { AttestationPolicy = disallowDebugging });
        /// disallowDebuggingHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.ToString()));
        /// </code>
        /// </remarks>
        public virtual async Task <AttestationResponse <PolicyResult> > SetPolicyAsync(
            AttestationType attestationType,
            string policyToSet,
            AsymmetricAlgorithm signingKey      = default,
            X509Certificate2 signingCertificate = default,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrEmpty(policyToSet))
            {
                throw new ArgumentException($"'{nameof(policyToSet)}' cannot be null or empty.", nameof(policyToSet));
            }

            if (signingKey is null && signingCertificate is not null || signingCertificate is null && signingKey is not null)
            {
                throw new ArgumentException($"If you specify '{nameof(signingKey)}' or '{nameof(signingCertificate)}', you must also specify '{nameof(signingCertificate)}' or '{nameof(signingKey)}'.");
            }

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(SetPolicy)}");
            scope.Start();
            try
            {
                AttestationToken tokenToSet;
                if (signingKey is null)
                {
                    tokenToSet = new UnsecuredAttestationToken(new StoredAttestationPolicy {
                        AttestationPolicy = policyToSet,
                    });
                }
                else
                {
                    tokenToSet = new SecuredAttestationToken(new StoredAttestationPolicy {
                        AttestationPolicy = policyToSet,
                    }, signingKey, signingCertificate);
                }

                var result = await _policyClient.SetAsync(attestationType, tokenToSet.ToString(), cancellationToken).ConfigureAwait(false);

                var token = new AttestationToken(result.Value.Token);
                if (_options.ValidateAttestationTokens)
                {
                    token.ValidateToken(GetSigners(), _options.ValidationCallback);
                }
                return(new AttestationResponse <PolicyResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Attest an Intel SGX enclave.
        /// </summary>
        /// <param name="quote">An Intel SGX "quote".
        /// See https://software.intel.com/content/www/us/en/develop/articles/code-sample-intel-software-guard-extensions-remote-attestation-end-to-end-example.html for more information.</param>
        /// <param name="initTimeData">Data provided when the enclave was created.</param>
        /// <param name="initTimeDataIsObject">true if the initTimeData parameter should be treated as an object, false if it should be treated as binary.</param>
        /// <param name="runTimeData">Data provided when the quote was generated.</param>
        /// <param name="runTimeDataIsObject">true if the runTimeData parameter should be treated as an object, false if it should be treated as binary.</param>
        /// <param name="async">true if the API call should be asynchronous, false otherwise.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel the request.</param>
        /// <returns>An <see cref="AttestationResponse{AttestationResult}"/> which contains the validated claims for the supplied <paramref name="quote"/>, <paramref name="runTimeData"/>, and <paramref name="initTimeData"/></returns>
        private async Task <AttestationResponse <AttestationResult> > AttestSgxEnclaveInternal(ReadOnlyMemory <byte> quote, BinaryData initTimeData, bool initTimeDataIsObject, BinaryData runTimeData, bool runTimeDataIsObject, bool async, CancellationToken cancellationToken = default)
        {
            Argument.AssertNotNull(runTimeData, nameof(runTimeData));
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationClient)}.{nameof(AttestSgxEnclave)}");
            scope.Start();
            try
            {
                var attestSgxEnclaveRequest = new AttestSgxEnclaveRequest
                {
                    Quote        = quote.ToArray(),
                    InitTimeData = initTimeData != null ? new InitTimeData
                    {
                        Data     = initTimeData.ToArray(),
                        DataType = initTimeDataIsObject ? DataType.Json : DataType.Binary,
                    } : null,
                    RuntimeData = runTimeData != null ? new RuntimeData
                    {
                        Data     = runTimeData.ToArray(),
                        DataType = runTimeDataIsObject ? DataType.Json : DataType.Binary,
                    } : null,
                };

                Response <AttestationResponse> response;
                if (async)
                {
                    response = await _restClient.AttestSgxEnclaveAsync(attestSgxEnclaveRequest, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    response = _restClient.AttestSgxEnclave(attestSgxEnclaveRequest, cancellationToken);
                }
                var attestationToken = new AttestationToken(response.Value.Token);

                if (_options.TokenOptions.ValidateToken)
                {
                    await attestationToken.ValidateTokenInternalAsync(_options.TokenOptions, await GetSignersAsync(cancellationToken).ConfigureAwait(false), async, cancellationToken).ConfigureAwait(false);
                }

                return(new AttestationResponse <AttestationResult>(response.GetRawResponse(), attestationToken));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 17
0
        /// <summary>
        /// Adds the specified new signing certificate to the set of policy management certificates.
        /// </summary>
        /// <param name="newSigningCertificate">The new certificate to add.</param>
        /// <param name="existingSigningKey">An existing key corresponding to the existing certificate.</param>
        /// <param name="existingSigningCertificate">One of the existing policy management certificates.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// </remarks>
        public virtual AttestationResponse <PolicyCertificatesModificationResult> AddPolicyManagementCertificate(
            X509Certificate2 newSigningCertificate,
            AsymmetricAlgorithm existingSigningKey,
            X509Certificate2 existingSigningCertificate,
            CancellationToken cancellationToken = default)
        {
            if (newSigningCertificate is null)
            {
                throw new ArgumentNullException(nameof(newSigningCertificate));
            }

            if (existingSigningKey is null)
            {
                throw new ArgumentNullException(nameof(existingSigningKey));
            }

            if (existingSigningCertificate is null)
            {
                throw new ArgumentNullException(nameof(existingSigningCertificate));
            }

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(AddPolicyManagementCertificate)}");
            scope.Start();
            try
            {
                var tokenToAdd = new SecuredAttestationToken(
                    new PolicyCertificateModification(newSigningCertificate),
                    existingSigningKey,
                    existingSigningCertificate);
                var result = _policyManagementClient.Add(tokenToAdd.ToString(), cancellationToken);
                var token  = new AttestationToken(result.Value.Token);
                if (_options.ValidateAttestationTokens)
                {
                    token.ValidateToken(GetSigners(), _options.ValidationCallback);
                }
                return(new AttestationResponse <PolicyCertificatesModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
 /// <summary>
 /// Returns the set of policy management certificates currently configured for the attestation service instance.
 ///
 /// If the service instance is running in AAD mode, this list will always be empty.
 /// </summary>
 /// <param name="cancellationToken">Cancellation token used to cancel the operation.</param>
 /// <returns>A set of <see cref="X509Certificate2"/> objects representing the set of root certificates for policy management.</returns>
 public virtual AttestationResponse <PolicyCertificatesResult> GetPolicyManagementCertificates(CancellationToken cancellationToken = default)
 {
     using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(GetPolicyManagementCertificates)}");
     scope.Start();
     try
     {
         var result = _policyManagementClient.Get(cancellationToken);
         var token  = new AttestationToken(result.Value.Token);
         if (_options.TokenOptions.ValidateToken)
         {
             token.ValidateToken(_options.TokenOptions, GetSigners(cancellationToken), cancellationToken);
         }
         return(new AttestationResponse <PolicyCertificatesResult>(result.GetRawResponse(), token));
     }
     catch (Exception ex)
     {
         scope.Failed(ex);
         throw;
     }
 }
Exemplo n.º 19
0
 /// <summary>
 /// Retrieves the attesttion policy for the specified <see cref="AttestationType"/>.
 /// </summary>
 /// <param name="certificateToAdd">Attestation Type to retrive.</param>
 /// <param name="cancellationToken"></param>
 /// <returns>An <see cref="AttestationResponse{PolicyCertificatesModificationResult}"/> with the policy for the specified attestation type.</returns>
 public virtual AttestationResponse <PolicyCertificatesModificationResult> RemovePolicyManagementCertificate(SecuredAttestationToken certificateToAdd, CancellationToken cancellationToken = default)
 {
     using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(RemovePolicyManagementCertificate)}");
     scope.Start();
     try
     {
         var result = _policyManagementClient.Remove(certificateToAdd.ToString(), cancellationToken);
         var token  = new AttestationToken(result.Value.Token);
         if (_options.ValidateAttestationTokens)
         {
             token.ValidateToken(GetSigners(), _options.ValidationCallback);
         }
         return(new AttestationResponse <PolicyCertificatesModificationResult>(result.GetRawResponse(), token));
     }
     catch (Exception ex)
     {
         scope.Failed(ex);
         throw;
     }
 }
Exemplo n.º 20
0
 /// <summary>
 /// Sets the attesttion policy for the specified <see cref="AttestationType"/>.
 /// </summary>
 /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be set.</param>
 /// <param name="policyToSet"><see cref="AttestationToken"/> specifying the new stored attestation policy.</param>
 /// <param name="cancellationToken"></param>
 /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
 public virtual AttestationResponse <PolicyResult> SetPolicy(AttestationType attestationType, AttestationToken policyToSet, CancellationToken cancellationToken = default)
 {
     using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(SetPolicy)}");
     scope.Start();
     try
     {
         var result = _policyClient.Set(attestationType, policyToSet.ToString(), cancellationToken);
         var token  = new AttestationToken(result.Value.Token);
         if (_options.ValidateAttestationTokens)
         {
             token.ValidateToken(GetSigners(), _options.ValidationCallback);
         }
         return(new AttestationResponse <PolicyResult>(result.GetRawResponse(), token));
     }
     catch (Exception ex)
     {
         scope.Failed(ex);
         throw;
     }
 }
Exemplo n.º 21
0
        /// <summary>
        /// Returns the set of policy management certificates currently configured for the attestation service.
        ///
        /// If the service is running in AAD mode, this list will be empty.
        /// </summary>
        /// <param name="cancellationToken">Cancellation token used to cancel the operation.</param>
        /// <returns>A set of <see cref="X509Certificate2"/> objects representing the set of root certificates for policy management.</returns>
        public virtual async Task <AttestationResponse <PolicyCertificatesResult> > GetPolicyManagementCertificatesAsync(CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(GetPolicyManagementCertificates)}");
            scope.Start();
            try
            {
                var result = await _policyManagementClient.GetAsync(cancellationToken).ConfigureAwait(false);

                var token = new AttestationToken(result.Value.Token);
                if (_options.ValidateAttestationTokens)
                {
                    token.ValidateToken(GetSigners(), _options.ValidationCallback);
                }
                return(new AttestationResponse <PolicyCertificatesResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
        /// <summary>
        /// Attest an Open Enclave enclave.
        /// </summary>
        /// <param name="report">An Open Enclave "report".
        /// See https://github.com/openenclave/openenclave for more information.</param>
        /// <param name="initTimeData"></param>
        /// <param name="initTimeDataIsObject"></param>
        /// <param name="runTimeData">Data provided when the quote was generated.</param>
        /// <param name="runTimeDataIsObject"></param>
        /// <param name="cancellationToken">Cancellation token used to cancel the request.</param>
        /// <returns></returns>
        public virtual async Task <AttestationResponse <AttestationResult> > AttestOpenEnclaveAsync(ReadOnlyMemory <byte> report, BinaryData initTimeData, bool initTimeDataIsObject, BinaryData runTimeData, bool runTimeDataIsObject, CancellationToken cancellationToken = default)
        {
            Argument.AssertNotNull(runTimeData, nameof(runTimeData));
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationClient)}.{nameof(AttestSgxEnclave)}");
            scope.Start();
            try
            {
                var response = await _restClient.AttestOpenEnclaveAsync(
                    new AttestOpenEnclaveRequest
                {
                    Report       = report.ToArray(),
                    InitTimeData = initTimeData != null ? new InitTimeData
                    {
                        Data     = initTimeData.ToArray(),
                        DataType = initTimeDataIsObject ? DataType.Json : DataType.Binary,
                    } : null,
                    RuntimeData = runTimeData != null ? new RuntimeData
                    {
                        Data     = runTimeData.ToArray(),
                        DataType = runTimeDataIsObject ? DataType.Json : DataType.Binary,
                    } : null,
                },
                    cancellationToken).ConfigureAwait(false);

                var attestationToken = new AttestationToken(response.Value.Token);

                if (_options.ValidateAttestationTokens)
                {
                    attestationToken.ValidateToken(GetSigners(), _options.ValidationCallback);
                }

                return(new AttestationResponse <AttestationResult>(response.GetRawResponse(), attestationToken));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 23
0
        /// <summary>
        /// Resets the policy for the specified <see cref="AttestationType"/> to the default value.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be reset.</param>
        /// <param name="signingKey">If provided, specifies the signing key used to sign the request to the attestation service.</param>
        /// <param name="signingCertificate">If provided, specifies the X.509 certificate which will be used to validate the request with the attestation service.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// The <paramref name="signingKey"/> and <paramref name="signingCertificate"/> parameters are optional, but if one is provided the other must also be provided.
        /// <para/>
        /// If the <paramref name="signingKey"/> and <paramref name="signingCertificate"/> parameters are not provided, then the policy document sent to the
        /// attestation service will be unsigned. Unsigned attestation policies are only allowed when the attestation instance is running in AAD mode - if the
        /// attestation instance is running in Isolated mode, then a signing key and signing certificate MUST be provided to ensure that the caller of the API is authorized to change policy.
        /// The <paramref name="signingCertificate"/> parameter MUST be one of the certificates returned by the <see cref="GetPolicyManagementCertificates(CancellationToken)"/> API.
        /// <para/>
        /// </remarks>
        ///
        public virtual AttestationResponse <PolicyResult> ResetPolicy(
            AttestationType attestationType,
            AsymmetricAlgorithm signingKey      = default,
            X509Certificate2 signingCertificate = default,
            CancellationToken cancellationToken = default)
        {
            if (signingKey is null && signingCertificate is not null || signingCertificate is null && signingKey is not null)
            {
                throw new ArgumentException($"If you specify '{nameof(signingKey)}' or '{nameof(signingCertificate)}', you must also specify '{nameof(signingCertificate)}' or '{nameof(signingKey)}'.");
            }

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(ResetPolicy)}");
            scope.Start();
            try
            {
                AttestationToken tokenToSet;
                if (signingKey is null)
                {
                    tokenToSet = new UnsecuredAttestationToken();
                }
                else
                {
                    tokenToSet = new SecuredAttestationToken(signingKey, signingCertificate);
                }

                var result = _policyClient.Reset(attestationType, tokenToSet.ToString(), cancellationToken);
                var token  = new AttestationToken(result.Value.Token);
                if (_options.ValidateAttestationTokens)
                {
                    token.ValidateToken(GetSigners(), _options.ValidationCallback);
                }
                return(new AttestationResponse <PolicyResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 24
0
        /// <summary>
        /// Retrieves the attesttion policy for the specified <see cref="AttestationType"/>.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> to retrive.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <param name="async">True if the call should be asynchronous.</param>
        /// <returns>An <see cref="AttestationResponse{String}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// This API returns the underlying attestation policy object stored in the attestation service for this <paramref name="attestationType"/>.
        ///
        /// The actual service response to the API is an RFC 7519 JSON Web Token (see https://tools.ietf.org/html/rfc7519"). This token can be retrieved from <see cref="AttestationResponse{T}.Token"/>.
        /// For the GetPolicy API, the body of the <see cref="AttestationResponse{T}.Token"/> is a <see cref="StoredAttestationPolicy"/> object, NOT a string.
        /// </remarks>
        private async Task <AttestationResponse <string> > GetPolicyInternalAsync(AttestationType attestationType, bool async, CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(GetPolicy)}");
            scope.Start();
            try
            {
                Response <PolicyResponse> result;
                if (async)
                {
                    result = await _policyClient.GetAsync(attestationType, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    result = _policyClient.Get(attestationType, cancellationToken);
                }

                var token = AttestationToken.Deserialize(result.Value.Token, _clientDiagnostics);
                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = await GetSignersAsync(async, cancellationToken).ConfigureAwait(false);

                    if (!await token.ValidateTokenInternal(_options.TokenOptions, signers, async, cancellationToken).ConfigureAwait(false))
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, token);
                    }
                }

                PolicyModificationResult policyResult = token.GetBody <PolicyModificationResult>();

                var response = new AttestationResponse <StoredAttestationPolicy>(result.GetRawResponse(), policyResult.PolicyToken);

                return(new AttestationResponse <string>(result.GetRawResponse(), token, response.Value.AttestationPolicy));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 25
0
        /// <summary>
        /// Sets the attesttion policy for the specified <see cref="AttestationType"/>.
        /// </summary>
        /// <param name="attestationType"><see cref="AttestationType"/> whose policy should be set.</param>
        /// <param name="policyToSet">Specifies the attestation policy to set.</param>
        /// <param name="signingKey">If provided, specifies the signing key used to sign the request to the attestation service.</param>
        /// <param name="cancellationToken">Cancellation token used to cancel this operation.</param>
        /// <returns>An <see cref="AttestationResponse{PolicyResult}"/> with the policy for the specified attestation type.</returns>
        /// <remarks>
        /// If the <paramref name="signingKey"/> parameter is not provided, then the policy document sent to the
        /// attestation service will be unsigned. Unsigned attestation policies are only allowed when the attestation instance is running in AAD mode - if the
        /// attestation instance is running in Isolated mode, then a signing key and signing certificate MUST be provided to ensure that the caller of the API is authorized to change policy.
        /// The <see cref="AttestationTokenSigningKey.Certificate"/> field MUST be one of the certificates returned by the <see cref="GetPolicyManagementCertificates(CancellationToken)"/> API.
        /// <para/>
        /// Clients need to be able to verify that the attestation policy document was not modified before the policy document was received by the attestation service's enclave.
        /// There are two properties provided in the [PolicyResult][attestation_policy_result] that can be used to verify that the service received the policy document:
        /// <list type="bullet">
        /// <item>
        /// <description><see cref="PolicyModificationResult.PolicySigner"/> - if the <see cref="SetPolicy(AttestationType, string, AttestationTokenSigningKey, CancellationToken)"/> call included a signing certificate, this will be the certificate provided at the time of the `SetPolicy` call. If no policy signer was set, this will be null. </description>
        /// </item>
        /// <item>
        /// <description><see cref="PolicyModificationResult.PolicyTokenHash"/> - this is the hash of the [JSON Web Token][json_web_token] sent to the service</description>
        /// </item>
        /// </list>
        /// To verify the hash, clients can generate an attestation token and verify the hash generated from that token:
        /// <code snippet="Snippet:VerifySigningHash">
        /// // The SetPolicyAsync API will create an AttestationToken signed with the TokenSigningKey to transmit the policy.
        /// // To verify that the policy specified by the caller was received by the service inside the enclave, we
        /// // verify that the hash of the policy document returned from the Attestation Service matches the hash
        /// // of an attestation token created locally.
        /// TokenSigningKey signingKey = new TokenSigningKey(&lt;Customer provided signing key&gt;, &lt;Customer provided certificate&gt;)
        /// var policySetToken = new AttestationToken(
        ///     BinaryData.FromObjectAsJson(new StoredAttestationPolicy { AttestationPolicy = attestationPolicy }),
        ///     signingKey);
        ///
        /// using var shaHasher = SHA256Managed.Create();
        /// byte[] attestationPolicyHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.Serialize()));
        ///
        /// Debug.Assert(attestationPolicyHash.SequenceEqual(setResult.Value.PolicyTokenHash.ToArray()));
        /// </code>
        ///
        /// If the signing key and certificate are not provided, then the SetPolicyAsync API will create an unsecured attestation token
        /// wrapping the attestation policy. To validate the <see cref="PolicyModificationResult.PolicyTokenHash"/> return value, a developer
        /// can create their own <see cref="AttestationToken"/> and create the hash of that.
        /// <code>
        /// using var shaHasher = SHA256Managed.Create();
        /// var policySetToken = new AttestationToken(new StoredAttestationPolicy { AttestationPolicy = disallowDebugging });
        /// disallowDebuggingHash = shaHasher.ComputeHash(Encoding.UTF8.GetBytes(policySetToken.ToString()));
        /// </code>
        /// </remarks>
        public virtual async Task <AttestationResponse <PolicyModificationResult> > SetPolicyAsync(
            AttestationType attestationType,
            string policyToSet,
            AttestationTokenSigningKey signingKey = default,
            CancellationToken cancellationToken   = default)
        {
            if (string.IsNullOrEmpty(policyToSet))
            {
                throw new ArgumentException($"'{nameof(policyToSet)}' cannot be null or empty.", nameof(policyToSet));
            }

            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(SetPolicy)}");
            scope.Start();
            try
            {
                AttestationToken tokenToSet = new AttestationToken(BinaryData.FromObjectAsJson(new StoredAttestationPolicy {
                    AttestationPolicy = policyToSet,
                }), signingKey);

                var result = await _policyClient.SetAsync(attestationType, tokenToSet.Serialize(), cancellationToken).ConfigureAwait(false);

                var token = AttestationToken.Deserialize(result.Value.Token, _clientDiagnostics);
                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = await GetSignersAsync(true, cancellationToken).ConfigureAwait(false);

                    if (!await token.ValidateTokenAsync(_options.TokenOptions, signers, cancellationToken).ConfigureAwait(false))
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, token);
                    }
                }
                return(new AttestationResponse <PolicyModificationResult>(result.GetRawResponse(), token));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
Exemplo n.º 26
0
        /// <summary>
        /// Returns the set of policy management certificates currently configured for the attestation service instance.
        ///
        /// If the service instance is running in AAD mode, this list will always be empty.
        /// </summary>
        /// <param name="cancellationToken">Cancellation token used to cancel the operation.</param>
        /// <param name="async">True if this request should be processed asyncly.</param>
        /// <returns>A set of <see cref="X509Certificate2"/> objects representing the set of root certificates for policy management.</returns>
        private async Task <AttestationResponse <IReadOnlyList <X509Certificate2> > > GetPolicyManagementCertificatesInternalAsync(bool async, CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(AttestationAdministrationClient)}.{nameof(GetPolicyManagementCertificates)}");
            scope.Start();
            try
            {
                Response <PolicyCertificatesResponse> result;
                if (async)
                {
                    result = await _policyManagementClient.GetAsync(cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    result = _policyManagementClient.Get(cancellationToken);
                }
                var token = AttestationToken.Deserialize(result.Value.Token);
                if (_options.TokenOptions.ValidateToken)
                {
                    var signers = await GetSignersAsync(async, cancellationToken).ConfigureAwait(false);

                    if (!await token.ValidateTokenInternal(_options.TokenOptions, signers, async, cancellationToken).ConfigureAwait(false))
                    {
                        AttestationTokenValidationFailedException.ThrowFailure(signers, token);
                    }
                }
                List <X509Certificate2> certificates = new List <X509Certificate2>();
                foreach (var cert in token.GetBody <PolicyCertificatesResult>().InternalPolicyCertificates.Keys)
                {
                    certificates.Add(new X509Certificate2(Convert.FromBase64String(cert.X5C[0])));
                }
                return(new AttestationResponse <IReadOnlyList <X509Certificate2> >(result.GetRawResponse(), token, certificates.AsReadOnly()));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="AttestationTokenValidationEventArgs"/> class.
 /// </summary>
 /// <param name="token">Attestation token for the client to validate.</param>
 /// <param name="signer">Attestation Signer which signed the token.</param>
 /// <param name="isRunningSynchronously">true if this event should be interpreted synchronously.</param>
 /// <param name="cancellationToken">Cancellation token, set if customer has canceled the request.</param>
 internal AttestationTokenValidationEventArgs(AttestationToken token, AttestationSigner signer, bool isRunningSynchronously, CancellationToken cancellationToken) : base(isRunningSynchronously, cancellationToken)
 {
     Token   = token;
     Signer  = signer;
     IsValid = true;
 }
 internal AttestationResponse(Response response, AttestationToken underlyingToken) : base()
 {
     _response = response;
     _token    = underlyingToken;
 }
 /// <summary>
 /// Represents a response from the Microsoft Azure Attestation service.
 /// </summary>
 /// <param name="response">The underlying response object corresponding to the original request,</param>
 /// <param name="underlyingToken">The attestation token returned from the attestation service.</param>
 /// <param name="body">The optional value of the body of the token to be returned to the customer. If none is provided, then the body will be retrieved from the attestation token.</param>
 internal AttestationResponse(Response response, AttestationToken underlyingToken, T body = default(T)) : base()
 {
     _response = response;
     _token    = underlyingToken;
     _body     = body;
 }
Exemplo n.º 30
0
 /// <summary>
 /// Create an instance of an AttestationResponse object for mocking purposes.
 /// </summary>
 /// <typeparam name="T">Type of the token body.</typeparam>
 /// <param name="response">Response type associated with the underlying response.</param>
 /// <param name="token">Attestation Token to be included in the response.</param>
 /// <param name="body">Optional body instance. If no body is provided, the body of the token is used.</param>
 /// <remarks>The <paramref name="body"/> parameter is provided to create an attestation response whose Value property is something other than the body of the token.</remarks>
 /// <returns>An <see cref="Attestation.AttestationResponse"/> object.</returns>
 public static AttestationResponse <T> AttestationResponse <T>(Response response, AttestationToken token, T body = default(T))
     where T : class =>
 new AttestationResponse <T>(response, token, body);