Visual Studio's AndroidApkSigner does not find key in keystore - visual-studio

I am getting this error when creating an APK within Visual Studio:
Failed to load signer "signer #1": C:\...\googleplay.keystore entry "googleplay" does not contain a key
I am a longtime ASP.NET developer who is familiar with Visual Studio but this is my first Xamarin project. (I am not using Android Studio.) I am trying to deploy the Android build to Google Play. I have never uploaded an APK to Google Play so I cannot use Visual Studio's automatic deployment; I must perform a manual deployment first per Google's and Microsoft's instructions.
I am running Visual Studio 2017 15.7.5 (latest) with JDK 1.8. My project is using NETStandard.Library 2.0.3, Xamarin.Forms 3.1.0, and Microsoft.EntityFrameworkCore 2.1.1.
This question is similar to this question that has no answers but I am getting the error from within Visual Studio. If this is a duplicate, I apologize but I am unable to add additional details on that question.
I am using Google Play App Signing. I have created a key through Google Play. I downloaded the certificate in .der format. I have used keytool (from c:\Program Files\Java\jdk1.8.0_172\bin) to convert the .der file to .keystore with the following command:
keytool -importcert -alias googleplay -file "C:\...\deployment_cert.der"
I have re-run this utility a few times changing the options thinking perhaps that there might be a problem with case sensitivity on the alias or special characters in the password that keytool prompts for. In this instance, the alias is all alpha, all lowercase, and the password is alpha-numeric all lowercase. keytool asks to trust this certificate and I press "y".
This results in a file named .keystore. I renamed this to googleplay.keystore and I moved it to a more appropriate place.
I can double-check that the googleplay alias is present in the keystore file by running this command:
C:\Program Files\Java\jdk1.8.0_172\bin>keytool -v -list -keystore "C:\...\googleplay.keystore" -alias googleplay
Enter keystore password:
Alias name: googleplay
Creation date: Jul 23, 2018
Entry type: trustedCertEntry
Owner: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Issuer: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Serial number: e8************************************8a
Valid from: Thu Jul 19 14:18:56 EDT 2018 until: Sun Jul 19 14:18:56 EDT 2048
Certificate fingerprints:
MD5: 0D:**:**:**:**:**:**:**:**:**:**:**:**:**:**:C8
SHA1: 11:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:CD
SHA256: D0:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:74
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]
The "googleplay" alias most definitely exists! The certificate fingerprints match the keys that Google gave me (redacted).
In Visual Studio, I set the solution configuration to Release mode, I cleaned my entire solution (successful), rebuilt my entire solution (successful), and then right-clicked my Android project and clicked Archive... per these instructions.
As a side-note, that Microsoft article is extremely frustrating because it does not mention signing or this issue, and their articles on signing do not match how Google Play operates and seem to assume you have a correct APK uploaded to Google Play already (bypassing the chicken-or-egg Catch-22).
At first all I got was The archiving process has failed. Please see the Errors section for more details. The Error List panel is empty. The Output panel just says "java.exe" exited with code 2. I went to Tools -> Options -> Projects and Solutions -> Build and Run and changed MSBuild project build output verbosity from Minimal to Diagnostic and repeated the last few steps (clean, rebuild, archive). Now, the Output panel (slightly redacted) says:
Using "AndroidApkSigner" task from assembly "C:\...\MSBuild\Xamarin\Android\Xamarin.Android.Build.Tasks.dll".
Task "AndroidApkSigner"
AndroidApkSigner:
ApkSignerJar: C:\Program Files (x86)\Android\android-sdk\build-tools\27.0.3\lib\apksigner.jar
ApkToSign: bin\Release\com.mycompany.myproject.apk
ManifestFile: obj\Release\android\AndroidManifest.xml
AdditionalArguments:
C:\Program Files\Java\jdk1.8.0_172\\bin\java.exe -jar "C:\Program Files (x86)\Android\android-sdk\build-tools\27.0.3\lib\apksigner.jar" sign --ks "C:\...\googleplay.keystore" --ks-pass pass:******** --ks-key-alias googleplay --key-pass pass:******** --min-sdk-version 19 --max-sdk-version 27 C:\...\myproject.Android\bin\Release\com.mycompany.myproject.apk
Failed to load signer "signer #1": C:\...\googleplay.keystore entry "googleplay" does not contain a key
"java.exe" exited with code 2.
Done executing task "AndroidApkSigner" -- FAILED.
Done building target "_Sign" in project "myproject.Android.csproj" -- FAILED.
Done building project "myproject.Android.csproj" -- FAILED.
Build FAILED.
From the above output you can see what the (redacted) values are in my project's property's Android Package Signing tab. Through trial and error I discovered that the Keystore Password, Alias, and Alias Password are all required. I set the Keystore Password and Alias Password to be the same, since there is only one password associated with this keystore. As mentioned above, the password is lower-alpha-numeric (no special characters following the advice from another SO question).
Why is AndroidApkSigner failing to find the key in the keystore for the provided alias when keytool finds the key without problem?
And, I can't be the only one with this problem? Deploying from Visual Studio to Google Play should be a fairly common workflow, but I am not finding anybody else (besides this other unanswered SO question) who is experiencing this issue. What am I doing wrong?

I have discovered the answer to my question. The documentation on the Android Developer site will not work with Visual Studio. The ApkSigner that comes with Xamarin does not know what to do with it. Instead, use this to create your own release key:
keytool -v -list -keystore c:\temp\myreleasekey.keystore -alias myalias -storetype pkcs12
Note the -storetype pkcs12 at the end. This command is also modified to (1) write the file somewhere besides Program Files, (2) uses .keystore extension which Visual Studio likes, and (3) avoids special characters in the alias, which Visual Studio does not like, from what I've read. (Avoid special characters in the password, too.)
Note, keytool is located in c:\Program Files\Java\jdk[version]\bin.
The Clue
When I followed the instructions on the documentation, I got a warning from keytool:
Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using keytool -importkeystore -srckeystore c:\temp\myreleasekey.jks -destkeystore c:\temp\myreleasekey.jks -deststoretype pkcs12.
I also got this warning when verifying the key is correct:
keytool -v -list -keystore c:\temp\myreleasekey.jks -alias myalias
If you have an existing key and need to convert it, follow the command in the warning.
Thank you:
I want to thank Nick for explaining the reasoning behind signing and differentiating between all the keys.
And thank you, Jon, for pointing me toward how to create my own private key.

The important fact you are missing:
Google Play never gives you a key you use to sign things. It only ever gives you certificates to verify with.
I'll start with the basics you probably know. In public key cryptography, there is a private key and a public key. Only the person who signs has the private key. Otherwise anyone could sign. The public key anyone can have. They can use it to check the signature is valid.
The upload_cert.der download only contains the public key. The reason Google Play lets you download it for verification. You can verify offline your signatures match what the Play Store expects. You probably never need to do this.
Why doesn't Google give you the signing key?
Google Play doesn't give you the private key for the upload certificate for 2 reasons.
Google doesn't have the private part of your upload key! You created the private key part of the upload key, when you enrolled in Google Play App signing. You never gave it to Google. All Google has is the public key part.
If Google did give it to you, the key would have no value. The whole point of the upload key is that even if a hacker breaks into you Play Console account they still cannot upload a new version of your app. They would need the upload key as well. The upload key means Google Play knows the app came from you. If they let you download the signing key from your account, then a hacker could just download it too. Then it would be worthless.
How do I get the upload key I need for signing?
So now the question you probably have is "how do I get the public key I need for signing?". The answer is "you create it". When you first upload your APK, that APK was signed with a key (Google insists on it). It was probably stored in your Visual Studio. That key becomes your upload key. Find where you kept it.
What if I lost it?
Now you might be in a place where you don't know where the key is that you originally used. This is the great thing about Google Play App Signing. If you were signing your app yourself and lost the signing key you would be stuck, you'd have to create a new app. But with Google Play App Signing you can contact Play Console support and they can help you. The process is on the help page.
Look at the section entitled "Create a new upload key". Notice step 1 is you create the key. Google still never has it.

Disable the option "sign the .APK file using the following keystore details."
you will get this option
right click on android project select properties goto Android Package Signing.

For me, the issue had something to do with the packaging/signing screen. I ended up removing everything from the signing screen, then building the archive.
Once built, I then clicked on the archive and hit distribute. At this point it asked me for the keystore and the password. I entered them and it signed the apk. I used that one to sideload the app and it worked great.

Related

Xamarin Forms - Android apk signing - Signing Packages Failed, keystore was tampered with

VS2022
I have succesfully built and archived my Xamarin.Forms app. I've used ad hoc distribution many times in this project, successfully.
With my last archive, it failed to sign the package, quoting the error Signing Packages Failed. 'Keystore was tampered with, or password was incorrect.'
I used this process after successfully archiving:
I click Distribute => Ad Hoc.
I select my signing Identity, and select a save location.
I am prompted for my password, which contains only 6 lower case letters.
I get an error:
Signing Packages Failed.
Keystore was tampered with, or password was incorrect.
Following other SO threads I have:
I've rebooted.
I've rebuilt and re-archived.
I have since deleted the keystore.
I've reinstalled xamarin forms after deleting the 'mono for android' folder.
Still, even with a brand new key (taking care for no special characters), the package signing fails.
I'm absolutely tearing my hair out - can anyone advise how to fix this ridiculous problem?

Visual Studio certificate error "the manifest designer could not import the certificate": What is the reason?

I am currently developing a WinUI 3 application, but I believe the details of the application type are not that important for the question I have.
The application comes with a "Package project" for publishing the application using MSIX:
In the editor for the "Package.appxmanifest" file in the package project there is a "Packaging" tab that has a "Choose certificate" button for selecting a ".pfx" certificate file.
How I obtained the ".pfx" file:
My IT department logged onto my machine while the application for the windows certificate store was open. There we added a new "Code signing" certicate under "Own certicates", but which is not issued by me, but by the IT department. They told me that this certicate should also be trusted by client machines, when I publish applications signed with it, because it was issued by them and so it has a valid trust chain. Later I exported a pfx file based on that certicate which I am trying to use now.
Now, upon selecting this .pfx file in Visual Studio on the 'Packaging' tab, I get this error message:
Unfortunately the "The manifest designer could not import the certificate" error message does not come with the exact reason what the problem is.
I am quite sure that my certificate has a valid date and also is made for "Code signing".
I already found out that there are other users wondering about how to fix the certificate if this message appears. But nobody seems to know how to get told about the exact problem.
Is there some way I can use Visual Studio or Powershell or some other tool to tell me what the exact problem is for the certificate when I select it in Visual Studio and this error appears? I would like to have more detailed information than "there is something wrong with the exported .pfx certificate" that I can give to my IT department.
I am aware that I can specify this setting in the project file of the packing project in order to stop the error from appearing:
<EnableSigningChecks>false</EnableSigningChecks>
But I would also be very interested to know what the exact problem is. Thank you.
Additional information:
To check the pfx certicate file, I also executed the "certutil" command (with the -v option) as indicated here: https://superuser.com/a/580698/543294 In the large text dump file I find an issuer that I also find in the list of Trusted Root Certification Authorities of the certicate management application.
Did you edit the Publisher attribute of the element in your Package.appxmanifest to match the Subject property of the certificate?
This should not generate the error above. In the worst case, it could let you build the package and then fail to install it due to this mismatch, or it could fail to build the package.
What I suspect is that IT gave you a code signing certificate that they generated (instead of buying it from a certified vendor). This is perfectly fine if you plan to deploy your application only internally, inside your company, as they can deploy that certificate to all other machines from the company, so those machines trust it.
However, if the certificate was indeed generated by IT, and they didn't deployed yet to your machine, VS might see this is not a trusted certificate and could give this error.
You can check if the certificate is trusted by opening certmgr console and searching for the certificate in the Trusted Root Certification Authorities hive.
If it is not there, double click the PFX file and follow the wizard (from steps #4) to install it.

signtool selects wrong (old) certificate for code-signing

I have a problem which I absolutely do not understand. A few days ago I issued a new codesigning certificate from our vendor (GlobalSign).
After logging in to the build server with the user that does the build / codesigning, I started certmgr, navigated to the Personal certificate storage and deleted the old certificate. Then I used the Import dialog to import the new certificate including it's private key.
A test build showed that signtool still uses the old certificate to sign the application. However, I'm unable to locate this certificate anywhere in the certmgr, not even by searching for that certificates SHA1 checksum.
After some googling I found this blogpost: http://qualapps.blogspot.de/2008/07/installing-code-signing-certificate.html
It stated the following:
Remove your old certificate. If you are renewing an existing certificate, then keeping the old certificates installed isn't usually useful, and having multiple certificates will break SIGNTOOL if signtool is searching the certificate store. Go to Control Panel / Internet Options / Content, click Certificates, select your old certificate, and click Remove. The old certificate will probably be on the Personal page if you allowed PVKIMPRT to decide where to put it.
I followed those instructions, but the only thing I can find is the new certificate.
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\signtool" sign /v /sm /n "my company name" /tr http://tsa.starfieldtech.com "the-setup.exe"
"my company name" is the name that is contained in both the old and the new certificate.
a. How can I find out where the old certificate is still stored and delete it?
b. How can I force signtool to use the new certificate, or at least fail?!
The workaround with using the PFX file and referencing to it is a good solution.
However, you may try the following:
add the parameter /s MY to the signtool parameters chain. "MY" links to the Personal store.
in certmgr.msc, look in other stores, if they do not contain a copy of the old certificate
add /a to the parameters chain. This will cause to "automatically select the best signing certificate" (whatever this means :))
you may wait until the old certificate expires. After that, it should automatically use only the new certificate
My situation seems similar, though in my case, putting the password for the certificate file in my build script wasn't an option. I was having trouble using any MMC snap-in to view (such as certmgr.msc) to view the certificate stores because Windows Server 2012 R2 wasn't allowing my non-admin build user to use the snap-ins. I resorted to trying a variation of a PowerShell script that I found here (https://social.technet.microsoft.com/Forums/windowsserver/en-US/7ed48943-22e2-4afd-aa77-2424d2a9eee1/how-to-delete-archived-certificates-using-the-certutil-command?forum=winserversecurity):
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "My","CurrentUser"
$MaxAllowedIncludeArchive = ([System.Security.Cryptography.X509Certificates.openflags]::MaxAllowed –bor [System.Security.Cryptography.X509Certificates.openflags]::IncludeArchived)
$store.Open($MaxAllowedIncludeArchive)
[System.Security.Cryptography.X509Certificates.X509Certificate2Collection] $certificates = $store.certificates
foreach ($cert in $certificates)
{
Write-Host $cert
}
$store.Close()
It showed me the certificate that was creating the conflict for me. (Strangely, trying to use certutil -viewstore My yielded a different set of certificates. (The placement of certificate stores is still unfortunately confusing to me.)
In my case, the problem was that I wanted a newer SHA256 certificate instead of my older SHA1 certificate so adding an appropriate /i argument to my signtool command (with the SHA256 issuer name) fixed my problem.

Signing Visual Studio manifest with PFX fails

I am having an issue that seems to have been discussed on several occasions, but alas no solution seems to work for me. I am running VS 2013 on VMWare (on Mac) trying to publish a ClickOnce project.
Initially, I installed certificate from Windows Explorer, chose it from Store, and then from drop down list below to get
An attempt was made to reference a token that does not exist
The error does not go away after delete / repeat cycle. It only works with my personally created PFX files (obviously, not good for deployment).
I then tried exporting, uninstalling, then installing using command line, namely
certutil -importPFX -user <name.pfx> AT_SIGNATURE
But the problem persisted. At some it started working, but then I got the
Cannot import the following key file: companyname.pfx. The key file may be password protected. To correct this, try to import the certificate again or manually install the certificate to the Strong Name CSP with the following key container name: VS_KEY_3E185446540E7F7A
Running
sn -i <certificate.pfx> VS_KEY_XXXXXXX
Does not change anything.
I feel really lost here and would highly appreciate any help.

TeamCity LocalService PFX Assembly Signing - Where to Install the Certificate

I've been looking around on this problem and whilst I've found a few "solutions" it seems that a lot of these "solutions" are stumbled upon or cannot adequtely explain what really worked.
I've tried a number of the solutions but I'm still having issues.
I've created a .PFX within Visual Studio. TeamCity and the Build Agent are all on my local development machine so there isn't any other PC involved in my situation.
When TeamCity tries to build this project I get an error:
error MSB3325: Cannot import the following key file: name.pfx. The key
file may be password protected. To correct this, try to import the
certificate again or manually install the certificate to the Strong
Name CSP with the following key container name:
VS_KEY_6E76201C7E991E97
Everything is running under Local System Account both Team City Server and the TeamCity Build Agent.
So where do I install the certificate? I've opened MMC.exe and imported it into a number of "obvious places" such as the Local Computer Certificate Snap-In. I tried importing it into the Personal and Trusted CA roots but neither of those worked.
So where on earth do you put it?
My solution to this was to create a new user account and import the pfx file under that user account. Then configure the TeamCity build agent on the machine to use that user as it's logon. For more steps on changing the credentials the build agent uses, see this post
Certificate is installed as a MSCP container (so it's not installed as a normal certificate).
Standard way is to use sn.exe but you can also use SnInstallPfx.exe
For more information, see the following blog article.

Resources