@@ -15,6 +15,7 @@ namespace VirtualClient
1515 using Azure . Security . KeyVault . Secrets ;
1616 using Polly ;
1717 using VirtualClient . Common . Extensions ;
18+ using VirtualClient . Identity ;
1819
1920 /// <summary>
2021 /// Provides methods for retrieving secrets, keys, and certificates from an Azure Key Vault.
@@ -211,40 +212,50 @@ public async Task<X509Certificate2> GetCertificateAsync(
211212 this . StoreDescription . ThrowIfNull ( nameof ( this . StoreDescription ) ) ;
212213 certName . ThrowIfNullOrWhiteSpace ( nameof ( certName ) , "The certificate name cannot be null or empty." ) ;
213214
214- // Use the keyVaultUri if provided as a parameter, otherwise use the store's EndpointUri
215215 Uri vaultUri = ! string . IsNullOrWhiteSpace ( keyVaultUri )
216216 ? new Uri ( keyVaultUri )
217217 : ( ( DependencyKeyVaultStore ) this . StoreDescription ) . EndpointUri ;
218218
219219 CertificateClient client = this . CreateCertificateClient ( vaultUri , ( ( DependencyKeyVaultStore ) this . StoreDescription ) . Credentials ) ;
220220
221+ var credentials = ( ( DependencyKeyVaultStore ) this . StoreDescription ) . Credentials ;
222+
223+ CertificateClient certificateClient = this . CreateCertificateClient ( vaultUri , credentials ) ;
224+ SecretClient secretClient = this . CreateSecretClient ( vaultUri , credentials ) ;
225+
221226 try
222227 {
223228 return await ( retryPolicy ?? KeyVaultManager . DefaultRetryPolicy ) . ExecuteAsync ( async ( ) =>
224229 {
225230 // Get the full certificate with private key (PFX) if requested
226231 if ( retrieveWithPrivateKey )
227232 {
228- X509Certificate2 privateKeyCert = await client
229- . DownloadCertificateAsync ( certName , cancellationToken : cancellationToken )
230- . ConfigureAwait ( false ) ;
233+ KeyVaultSecret secret = await secretClient . GetSecretAsync ( certName , cancellationToken : cancellationToken ) ;
234+
235+ if ( secret ? . Value == null )
236+ {
237+ throw new DependencyException ( $ "Secret for certificate '{ certName } ' not found in vault '{ vaultUri } '.") ;
238+ }
239+
240+ byte [ ] pfxBytes = Convert . FromBase64String ( secret . Value ) ;
231241
232- if ( privateKeyCert is null || ! privateKeyCert . HasPrivateKey )
242+ X509Certificate2 pfxCertificate = CertificateLoaderHelper . LoadPkcs12 (
243+ pfxBytes ,
244+ string . Empty ,
245+ X509KeyStorageFlags . Exportable | X509KeyStorageFlags . PersistKeySet ) ;
246+
247+ if ( ! pfxCertificate . HasPrivateKey )
233248 {
234- throw new DependencyException ( "Failed to retrieve certificate content with private key.") ;
249+ throw new DependencyException ( $ "Certificate ' { certName } ' does not contain a private key.") ;
235250 }
236251
237- return privateKeyCert ;
252+ return pfxCertificate ;
238253 }
239254 else
240255 {
241- // If private key not needed, load cert from PublicBytes
242- KeyVaultCertificateWithPolicy cert = await client . GetCertificateAsync ( certName , cancellationToken : cancellationToken ) ;
243- #if NET9_0_OR_GREATER
244- return X509CertificateLoader . LoadCertificate ( cert . Cer ) ;
245- #elif NET8_0_OR_GREATER
246- return new X509Certificate2 ( cert . Cer ) ;
247- #endif
256+ // Public certificate only
257+ KeyVaultCertificateWithPolicy certBundle = await certificateClient . GetCertificateAsync ( certName , cancellationToken : cancellationToken ) ;
258+ return CertificateLoaderHelper . LoadPublic ( certBundle . Cer ) ;
248259 }
249260 } ) . ConfigureAwait ( false ) ;
250261 }
@@ -269,13 +280,6 @@ public async Task<X509Certificate2> GetCertificateAsync(
269280 ex ,
270281 ErrorReason . HttpNonSuccessResponse ) ;
271282 }
272- catch ( Exception ex )
273- {
274- throw new DependencyException (
275- $ "Failed to get certificate '{ certName } ' from vault '{ vaultUri } '.",
276- ex ,
277- ErrorReason . HttpNonSuccessResponse ) ;
278- }
279283 }
280284
281285 /// <summary>
@@ -328,4 +332,4 @@ private void ValidateKeyVaultStore()
328332 }
329333 }
330334 }
331- }
335+ }
0 commit comments