Issue with Certificate Upload - "Invalid Credential" Error

I have used Cert-tools to create unsigned certificates and Cert-issuer (with Ethereum) to generate signed certificates.

However, when I upload the signed certificate to the app, I encounter the following error:
“Invalid Credential”

I would appreciate any guidance on resolving this issue.

Additionally, I would like to know:

  1. How to generate the Issuer URL?
  2. How to generate a one-time code for the certificates?

Thank you for your help!

@lemoustachiste

The error should be visible in the browser console.

Your issuer URL should be the URL of your issuer profile. It can be a DID. You can look at a hybrid profile here: https://www.blockcerts.org/samples/3.0/issuer-blockcerts.json

Your issuer profile should reference a public key listed in verificationMethod and available in say assertionMethod.

That same key should be used in the proof.verificationMethod.

That key should be presented in such format (JWK is fine) that the verifier can transform the public key into the issuing address used for the blockchain network of the transaction.

You should host your document somewhere accessible from the web (no CORS).

How to generate a one-time code for the certificates?

I’m not sure what you mean by this.

@lemoustachiste

Thanks for the quick response
Regarding the onetime code and issuer url the following forum help me alot

However i just want to know can i verify the certificate which i generated using ethereum in android-wallet and ios-wallet ?

Is ios-wallet accepting V3 certificates ?

Yes, both apps are compatible with v3

@lemoustachiste
But when i try to validate certificate it works well in site

But when i try to validate the same certificate in the mobile i’m facing an error as show in the image

Just to confirm, this is the Android app, latest version?

I have replicated the issue, I will take a deeper look at it.

Hey,

so I believe I have found the issue.

If you pull up JSON-LD Playground and paste your certificate in, then take a look at the canonized tab, you’ll see a safe mode error, which means that this property didn’t get properly hashed when issuing (last time I checked the pyld library safe mode wasn’t implemented so it’s not failing at issuance time).

You’ll need to define the key college as a jsonld object into your context and issue again.

The fact that it passes on blockcerts.org is more the bug than the other way around so I’m looking into that.

Hey @lemoustachiste

I addressed the issue you previously mentioned regarding the college and have issued a new certificate. The JSON file for the certificate has been validated in the JSON-LD Playground, and no errors were detected there. Additionally, I didn’t encounter any errors in Blockcerts.

However, when I try to verify the same certificate using cert-verifier-js, I’m still facing the following issue:
“Merkle root does not match remote hash.”

Could you please help me understand why this discrepancy might be occurring? Let me know if you need any additional details or files to investigate further.

Have you re-issued the credential with the new context? The proof value can change because the normalization is different due to the new keys that were specified, so if you modify your context you will need to re-issue all credentials bound to that context.

Yes i have re-issued the credential yesterday

I have created the new template and created unsigned certificate using cert-tools and issued the signed certificate using cert-issuer.

Here is my new certificate

I think you need to look at what’s being serialized in the jsonld playground, in cert-issuer (cert-issuer/cert_issuer/normalization_handler.py at master · blockchain-certificates/cert-issuer · GitHub) and cert-verifier-js (technically it’s in the MerkleProof package: jsonld-signatures-merkleproof2019/src/inspectors/computeLocalHash.ts at master · blockchain-certificates/jsonld-signatures-merkleproof2019 · GitHub).

You’ll need to run local copies to be able to print out the results and this tool is useful for comparing texts: https://text-compare.com/

I’m sorry I don’t have more time to do it myself.

Hi @lemoustachiste


I have printed the normalizedDocument in both cert-issuer and jsonld-signatures-merkleproof2019
and seems both texts are identical and i still face the Merkle root does not match remote hash error.

For your refere

<ecdsa-koblitz-pubkey:mkwntSiQmc14H65YxwckLenxY3DsEpvFbe> <http://schema.org/alumniOf> <https://www.**********.com/> .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <http://schema.org/keywords> "AI/ML/BigData" .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/blockcerts#BlockcertsCredential> .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <https://w3id.org/openbadges#salt> "47a8406b-0ad8-4dc8-bd04-8b5653bcd592" .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <https://w3id.org/security#nonce> "E17WPV96CM" .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <https://www.w3.org/2018/credentials#credentialSubject> <ecdsa-koblitz-pubkey:mkwntSiQmc14H65YxwckLenxY3DsEpvFbe> .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <https://www.w3.org/2018/credentials#expirationDate> "2025-01-21T18:09:45Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <https://www.w3.org/2018/credentials#issuanceDate> "2025-01-20T18:34:04Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<urn:uuid:f6c56398-1b50-4eb1-b423-b1595fa442f8> <https://www.w3.org/2018/credentials#issuer> <https://raw.githubusercontent.com/sreenumalae/DataStorage/main/issuer.json> .

@lemoustachiste

I am currently using the Ethereum testnet Sepolia.

From my debugging, I noticed that the remote hash is undefined.

This suggests that the Ethereum testnet Sepolia API might not be working as expected.

After i updated the following code everything works as smooth

function getTransactionServiceURL$1(chain) {
      const baseUrl = getApiBaseURL$1(chain);
      if(chain =="ethsepolia"){
        return `${baseUrl}&action=eth_getTransactionByHash&txhash=${TRANSACTION_ID_PLACEHOLDER$2}&apikey=***YOUR_API_KEY****`;
      }
      else{
        return `${baseUrl}&action=eth_getTransactionByHash&txhash=${TRANSACTION_ID_PLACEHOLDER$2}`;
      }
  }

We need to add the api key if the chain is ethsepolia while getting the remote hash.