Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

chrome extension says CRX_REQUIRED_PROOF_MISSING while installing

Hi I have Just created a chrome extension for internal Use of company, I don't want to publish that and want to pass to my fellow collegues when i have packed that extension in my local chrome it gives me ERROR saying that CRX_REQUIRED_PROOF_MISSING i am not getting enough thing about this error, please help me in this issue. enter image description here

like image 951
ThinkTank Avatar asked Aug 09 '19 07:08

ThinkTank


People also ask

Why I Cannot install extensions in Chrome?

Make sure you have the latest version of Chrome. Learn how to update Chrome. If you're using a work or school computer, your administrator might not let you install items from the Chrome Web Store. For more help, contact your administrator.

How do I force Chrome extensions to install?

Go to the app or extension that you want to automatically install. Under Installation policy, choose Force install or Force install + pin. Click Save.


2 Answers

You need to modify your local Policies to allow installs from a custom URL base you need to specify. This info is saved in a JSON on Linux or the Registry on Windows. See this link here Set Chrome app and extension policies (Windows) and then click Extension Install Sources to learn how to whitelist your Extensions' URLs. Then use Extension Install Allowlist to enable specific Extension IDs.

Also to get stable extension IDs, use the Chrome packer which means execute chrome with command line chrome --pack-extension="path\to\extension\folder" --pack-extension-key="path\to\file.pem". As long as the .pem is reused, this will produce a proper .crx with a stable ID that you can whitelist and will stick as you update.

To read the ID from the .CRX this is my C# code:

private static string ReadExtensionIdFromCrx3(string path)
{
    using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
    return ReadExtensionIdFromCrx3(stream);
}

private static string ReadExtensionIdFromCrx3(Stream stream)
{
    using var reader = new BinaryReader(stream);
    using var netreader = new BinaryReaderNetOrder(stream);
    var magic = netreader.ReadInt32();
    if (magic != 0x43723234)
    {
        throw new InvalidDataException();
    }

    var version = netreader.ReadInt32();
    if (version != 0x03000000)
    {
        throw new InvalidDataException();
    }

    var headerSize = reader.ReadInt32();
    var headerBytes = reader.ReadBytes(headerSize);

    var header = CrxFileHeader.Parser.ParseFrom(headerBytes);
    var first = header.Sha256WithRsa[0];
    var halfHashed = new byte[16];
    using (var hash = SHA256.Create())
    {
        var hashed = hash.ComputeHash(first.PublicKey.ToByteArray());
        Array.Copy(hashed, 0, halfHashed, 0, halfHashed.Length);
    }

    var sb = new StringBuilder();
    for (int it = 0; it < halfHashed.Length; ++it)
    {
        sb.Append((char)('a' + (halfHashed[it] / 16)));
        sb.Append((char)('a' + (halfHashed[it] % 16)));
    }
    return sb.ToString();
}

and also you can use this minimalistic Network Order Bytereader.

public class BinaryReaderNetOrder : BinaryReader
{
    public BinaryReaderNetOrder(Stream stream) : base(stream) { }

    public override short ReadInt16()
    {
        return BitConverter.ToInt16(ReadNetOrder(2), 0);
    }

    public override int ReadInt32()
    {
        return BitConverter.ToInt32(ReadNetOrder(4), 0);
    }

    public override long ReadInt64()
    {
        return BitConverter.ToInt64(ReadNetOrder(8), 0);
    }

    public override ushort ReadUInt16()
    {
        return BitConverter.ToUInt16(ReadNetOrder(2), 0);
    }

    public override uint ReadUInt32()
    {
        return BitConverter.ToUInt32(ReadNetOrder(4), 0);
    }

    public override ulong ReadUInt64()
    {
        return BitConverter.ToUInt64(ReadNetOrder(8), 0);
    }

    public override float ReadSingle()
    {
        return BitConverter.ToSingle(ReadNetOrder(4), 0);
    }

    public override double ReadDouble()
    {
        return BitConverter.ToDouble(ReadNetOrder(8), 0);
    }

    public override byte[] ReadBytes(int count)
    {
        var data = base.ReadBytes(count);
        if (data.Length < count)
        {
            throw new EndOfStreamException();
        }
        if (data.Length > count)
        {
            throw new IOException();
        }
        return data;
    }

    private byte[] ReadNetOrder(int count)
    {
        if (count < 2 || count > 8)
        {
            throw new ArgumentOutOfRangeException(nameof(count));
        }

        var data = ReadBytes(count);
        if (BitConverter.IsLittleEndian)
        {
            Array.Reverse(data);
        }
        return data;
    }
}

You'll also need the Protobuf header definition:

// <auto-generated>
//     Generated by the protocol buffer compiler.  DO NOT EDIT!
//     source: test.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code

using pb = Google.Protobuf;
using pbc = Google.Protobuf.Collections;
using pbr = Google.Protobuf.Reflection;
using scg = System.Collections.Generic;
/// <summary>Holder for reflection information generated from test.proto</summary>
public static partial class TestReflection
{

    #region Descriptor
    /// <summary>File descriptor for test.proto</summary>
    public static pbr::FileDescriptor Descriptor
    {
        get { return descriptor; }
    }
    private static pbr::FileDescriptor descriptor;

    static TestReflection()
    {
        byte[] descriptorData = System.Convert.FromBase64String(
            string.Concat(
              "Cgp0ZXN0LnByb3RvIooBCg1DcnhGaWxlSGVhZGVyEiwKD3NoYTI1Nl93aXRo",
              "X3JzYRgCIAMoCzITLkFzeW1tZXRyaWNLZXlQcm9vZhIuChFzaGEyNTZfd2l0",
              "aF9lY2RzYRgDIAMoCzITLkFzeW1tZXRyaWNLZXlQcm9vZhIbChJzaWduZWRf",
              "aGVhZGVyX2RhdGEYkE4gASgMIjsKEkFzeW1tZXRyaWNLZXlQcm9vZhISCgpw",
              "dWJsaWNfa2V5GAEgASgMEhEKCXNpZ25hdHVyZRgCIAEoDCIcCgpTaWduZWRE",
              "YXRhEg4KBmNyeF9pZBgBIAEoDGIGcHJvdG8z"));
        descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
            new pbr::FileDescriptor[] { },
            new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
      new pbr::GeneratedClrTypeInfo(typeof(CrxFileHeader), CrxFileHeader.Parser, new[]{ "Sha256WithRsa", "Sha256WithEcdsa", "SignedHeaderData" }, null, null, null, null),
      new pbr::GeneratedClrTypeInfo(typeof(AsymmetricKeyProof), AsymmetricKeyProof.Parser, new[]{ "PublicKey", "Signature" }, null, null, null, null),
      new pbr::GeneratedClrTypeInfo(typeof(SignedData), SignedData.Parser, new[]{ "CrxId" }, null, null, null, null)
            }));
    }
    #endregion

}
#region Messages
public sealed partial class CrxFileHeader : pb::IMessage<CrxFileHeader>
{
    private static readonly pb::MessageParser<CrxFileHeader> _parser = new pb::MessageParser<CrxFileHeader>(() => new CrxFileHeader());
    private pb::UnknownFieldSet _unknownFields;
    [DebuggerNonUserCode]
    public static pb::MessageParser<CrxFileHeader> Parser { get { return _parser; } }

    [DebuggerNonUserCode]
    public static pbr::MessageDescriptor Descriptor
    {
        get { return TestReflection.Descriptor.MessageTypes[0]; }
    }

    [DebuggerNonUserCode]
    pbr::MessageDescriptor pb::IMessage.Descriptor
    {
        get { return Descriptor; }
    }

    [DebuggerNonUserCode]
    public CrxFileHeader()
    {
        OnConstruction();
    }

    partial void OnConstruction();

    [DebuggerNonUserCode]
    public CrxFileHeader(CrxFileHeader other) : this()
    {
        sha256WithRsa_ = other.sha256WithRsa_.Clone();
        sha256WithEcdsa_ = other.sha256WithEcdsa_.Clone();
        signedHeaderData_ = other.signedHeaderData_;
        _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
    }

    [DebuggerNonUserCode]
    public CrxFileHeader Clone()
    {
        return new CrxFileHeader(this);
    }

    /// <summary>Field number for the "sha256_with_rsa" field.</summary>
    public const int Sha256WithRsaFieldNumber = 2;
    private static readonly pb::FieldCodec<AsymmetricKeyProof> _repeated_sha256WithRsa_codec
        = pb::FieldCodec.ForMessage(18, AsymmetricKeyProof.Parser);
    private readonly pbc::RepeatedField<AsymmetricKeyProof> sha256WithRsa_ = new pbc::RepeatedField<AsymmetricKeyProof>();
    /// <summary>
    /// PSS signature with RSA public key. The public key is formatted as a
    /// X.509 SubjectPublicKeyInfo block, as in CRXâ‚‚. In the common case of a
    /// developer key proof, the first 128 bits of the SHA-256 hash of the 
    /// public key must equal the crx_id.
    /// </summary>
    [DebuggerNonUserCode]
    public pbc::RepeatedField<AsymmetricKeyProof> Sha256WithRsa
    {
        get { return sha256WithRsa_; }
    }

    /// <summary>Field number for the "sha256_with_ecdsa" field.</summary>
    public const int Sha256WithEcdsaFieldNumber = 3;
    private static readonly pb::FieldCodec<AsymmetricKeyProof> _repeated_sha256WithEcdsa_codec
        = pb::FieldCodec.ForMessage(26, AsymmetricKeyProof.Parser);
    private readonly pbc::RepeatedField<AsymmetricKeyProof> sha256WithEcdsa_ = new pbc::RepeatedField<AsymmetricKeyProof>();
    /// <summary>
    /// ECDSA signature, using the NIST P-256 curve. Public key appears in
    /// named-curve format.
    /// The pinned algorithm will be this, at least on 2017-01-01.
    /// </summary>
    [DebuggerNonUserCode]
    public pbc::RepeatedField<AsymmetricKeyProof> Sha256WithEcdsa
    {
        get { return sha256WithEcdsa_; }
    }

    /// <summary>Field number for the "signed_header_data" field.</summary>
    public const int SignedHeaderDataFieldNumber = 10000;
    private pb::ByteString signedHeaderData_ = pb::ByteString.Empty;
    /// <summary>
    /// The binary form of a SignedData message. We do not use a nested 
    /// SignedData message, as handlers of this message must verify the proofs
    /// on exactly these bytes, so it is convenient to parse in two steps.
    ///
    /// All proofs in this CrxFile message are on the value
    /// "CRX3 SignedData\x00" + signed_header_size + signed_header_data +
    /// archive, where "\x00" indicates an octet with value 0, "CRX3 SignedData"
    /// is encoded using UTF-8, signed_header_size is the size in octets of the
    /// contents of this field and is encoded using 4 octets in little-endian
    /// order, signed_header_data is exactly the content of this field, and
    /// archive is the remaining contents of the file following the header.
    /// </summary>
    [DebuggerNonUserCode]
    public pb::ByteString SignedHeaderData
    {
        get { return signedHeaderData_; }
        set
        {
            signedHeaderData_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
        }
    }

    [DebuggerNonUserCode]
    public override bool Equals(object other)
    {
        return Equals(other as CrxFileHeader);
    }

    [DebuggerNonUserCode]
    public bool Equals(CrxFileHeader other)
    {
        if (ReferenceEquals(other, null))
        {
            return false;
        }
        if (ReferenceEquals(other, this))
        {
            return true;
        }
        if (!sha256WithRsa_.Equals(other.sha256WithRsa_)) return false;
        if (!sha256WithEcdsa_.Equals(other.sha256WithEcdsa_)) return false;
        if (SignedHeaderData != other.SignedHeaderData) return false;
        return Equals(_unknownFields, other._unknownFields);
    }

    [DebuggerNonUserCode]
    public override int GetHashCode()
    {
        int hash = 1;
        hash ^= sha256WithRsa_.GetHashCode();
        hash ^= sha256WithEcdsa_.GetHashCode();
        if (SignedHeaderData.Length != 0) hash ^= SignedHeaderData.GetHashCode();
        if (_unknownFields != null)
        {
            hash ^= _unknownFields.GetHashCode();
        }
        return hash;
    }

    [DebuggerNonUserCode]
    public override string ToString()
    {
        return pb::JsonFormatter.ToDiagnosticString(this);
    }

    [DebuggerNonUserCode]
    public void WriteTo(pb::CodedOutputStream output)
    {
        sha256WithRsa_.WriteTo(output, _repeated_sha256WithRsa_codec);
        sha256WithEcdsa_.WriteTo(output, _repeated_sha256WithEcdsa_codec);
        if (SignedHeaderData.Length != 0)
        {
            output.WriteRawTag(130, 241, 4);
            output.WriteBytes(SignedHeaderData);
        }
        if (_unknownFields != null)
        {
            _unknownFields.WriteTo(output);
        }
    }

    [DebuggerNonUserCode]
    public int CalculateSize()
    {
        int size = 0;
        size += sha256WithRsa_.CalculateSize(_repeated_sha256WithRsa_codec);
        size += sha256WithEcdsa_.CalculateSize(_repeated_sha256WithEcdsa_codec);
        if (SignedHeaderData.Length != 0)
        {
            size += 3 + pb::CodedOutputStream.ComputeBytesSize(SignedHeaderData);
        }
        if (_unknownFields != null)
        {
            size += _unknownFields.CalculateSize();
        }
        return size;
    }

    [DebuggerNonUserCode]
    public void MergeFrom(CrxFileHeader other)
    {
        if (other == null)
        {
            return;
        }
        sha256WithRsa_.Add(other.sha256WithRsa_);
        sha256WithEcdsa_.Add(other.sha256WithEcdsa_);
        if (other.SignedHeaderData.Length != 0)
        {
            SignedHeaderData = other.SignedHeaderData;
        }
        _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
    }

    [DebuggerNonUserCode]
    public void MergeFrom(pb::CodedInputStream input)
    {
        uint tag;
        while ((tag = input.ReadTag()) != 0)
        {
            switch (tag)
            {
                default:
                    _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
                    break;
                case 18:
                    {
                        sha256WithRsa_.AddEntriesFrom(input, _repeated_sha256WithRsa_codec);
                        break;
                    }
                case 26:
                    {
                        sha256WithEcdsa_.AddEntriesFrom(input, _repeated_sha256WithEcdsa_codec);
                        break;
                    }
                case 80002:
                    {
                        SignedHeaderData = input.ReadBytes();
                        break;
                    }
            }
        }
    }

}

public sealed partial class AsymmetricKeyProof : pb::IMessage<AsymmetricKeyProof>
{
    private static readonly pb::MessageParser<AsymmetricKeyProof> _parser = new pb::MessageParser<AsymmetricKeyProof>(() => new AsymmetricKeyProof());
    private pb::UnknownFieldSet _unknownFields;
    [DebuggerNonUserCode]
    public static pb::MessageParser<AsymmetricKeyProof> Parser { get { return _parser; } }

    [DebuggerNonUserCode]
    public static pbr::MessageDescriptor Descriptor
    {
        get { return TestReflection.Descriptor.MessageTypes[1]; }
    }

    [DebuggerNonUserCode]
    pbr::MessageDescriptor pb::IMessage.Descriptor
    {
        get { return Descriptor; }
    }

    [DebuggerNonUserCode]
    public AsymmetricKeyProof()
    {
        OnConstruction();
    }

    partial void OnConstruction();

    [DebuggerNonUserCode]
    public AsymmetricKeyProof(AsymmetricKeyProof other) : this()
    {
        publicKey_ = other.publicKey_;
        signature_ = other.signature_;
        _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
    }

    [DebuggerNonUserCode]
    public AsymmetricKeyProof Clone()
    {
        return new AsymmetricKeyProof(this);
    }

    /// <summary>Field number for the "public_key" field.</summary>
    public const int PublicKeyFieldNumber = 1;
    private pb::ByteString publicKey_ = pb::ByteString.Empty;
    [DebuggerNonUserCode]
    public pb::ByteString PublicKey
    {
        get { return publicKey_; }
        set
        {
            publicKey_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
        }
    }

    /// <summary>Field number for the "signature" field.</summary>
    public const int SignatureFieldNumber = 2;
    private pb::ByteString signature_ = pb::ByteString.Empty;
    [DebuggerNonUserCode]
    public pb::ByteString Signature
    {
        get { return signature_; }
        set
        {
            signature_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
        }
    }

    [DebuggerNonUserCode]
    public override bool Equals(object other)
    {
        return Equals(other as AsymmetricKeyProof);
    }

    [DebuggerNonUserCode]
    public bool Equals(AsymmetricKeyProof other)
    {
        if (ReferenceEquals(other, null))
        {
            return false;
        }
        if (ReferenceEquals(other, this))
        {
            return true;
        }
        if (PublicKey != other.PublicKey) return false;
        if (Signature != other.Signature) return false;
        return Equals(_unknownFields, other._unknownFields);
    }

    [DebuggerNonUserCode]
    public override int GetHashCode()
    {
        int hash = 1;
        if (PublicKey.Length != 0) hash ^= PublicKey.GetHashCode();
        if (Signature.Length != 0) hash ^= Signature.GetHashCode();
        if (_unknownFields != null)
        {
            hash ^= _unknownFields.GetHashCode();
        }
        return hash;
    }

    [DebuggerNonUserCode]
    public override string ToString()
    {
        return pb::JsonFormatter.ToDiagnosticString(this);
    }

    [DebuggerNonUserCode]
    public void WriteTo(pb::CodedOutputStream output)
    {
        if (PublicKey.Length != 0)
        {
            output.WriteRawTag(10);
            output.WriteBytes(PublicKey);
        }
        if (Signature.Length != 0)
        {
            output.WriteRawTag(18);
            output.WriteBytes(Signature);
        }
        if (_unknownFields != null)
        {
            _unknownFields.WriteTo(output);
        }
    }

    [DebuggerNonUserCode]
    public int CalculateSize()
    {
        int size = 0;
        if (PublicKey.Length != 0)
        {
            size += 1 + pb::CodedOutputStream.ComputeBytesSize(PublicKey);
        }
        if (Signature.Length != 0)
        {
            size += 1 + pb::CodedOutputStream.ComputeBytesSize(Signature);
        }
        if (_unknownFields != null)
        {
            size += _unknownFields.CalculateSize();
        }
        return size;
    }

    [DebuggerNonUserCode]
    public void MergeFrom(AsymmetricKeyProof other)
    {
        if (other == null)
        {
            return;
        }
        if (other.PublicKey.Length != 0)
        {
            PublicKey = other.PublicKey;
        }
        if (other.Signature.Length != 0)
        {
            Signature = other.Signature;
        }
        _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
    }

    [DebuggerNonUserCode]
    public void MergeFrom(pb::CodedInputStream input)
    {
        uint tag;
        while ((tag = input.ReadTag()) != 0)
        {
            switch (tag)
            {
                default:
                    _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
                    break;
                case 10:
                    {
                        PublicKey = input.ReadBytes();
                        break;
                    }
                case 18:
                    {
                        Signature = input.ReadBytes();
                        break;
                    }
            }
        }
    }

}

public sealed partial class SignedData : pb::IMessage<SignedData>
{
    private static readonly pb::MessageParser<SignedData> _parser = new pb::MessageParser<SignedData>(() => new SignedData());
    private pb::UnknownFieldSet _unknownFields;
    [DebuggerNonUserCode]
    public static pb::MessageParser<SignedData> Parser { get { return _parser; } }

    [DebuggerNonUserCode]
    public static pbr::MessageDescriptor Descriptor
    {
        get { return TestReflection.Descriptor.MessageTypes[2]; }
    }

    [DebuggerNonUserCode]
    pbr::MessageDescriptor pb::IMessage.Descriptor
    {
        get { return Descriptor; }
    }

    [DebuggerNonUserCode]
    public SignedData()
    {
        OnConstruction();
    }

    partial void OnConstruction();

    [DebuggerNonUserCode]
    public SignedData(SignedData other) : this()
    {
        crxId_ = other.crxId_;
        _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
    }

    [DebuggerNonUserCode]
    public SignedData Clone()
    {
        return new SignedData(this);
    }

    /// <summary>Field number for the "crx_id" field.</summary>
    public const int CrxIdFieldNumber = 1;
    private pb::ByteString crxId_ = pb::ByteString.Empty;
    /// <summary>
    /// This is simple binary, not UTF-8 encoded mpdecimal; i.e. it is exactly
    /// 16 bytes long.
    /// </summary>
    [DebuggerNonUserCode]
    public pb::ByteString CrxId
    {
        get { return crxId_; }
        set
        {
            crxId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
        }
    }

    [DebuggerNonUserCode]
    public override bool Equals(object other)
    {
        return Equals(other as SignedData);
    }

    [DebuggerNonUserCode]
    public bool Equals(SignedData other)
    {
        if (ReferenceEquals(other, null))
        {
            return false;
        }
        if (ReferenceEquals(other, this))
        {
            return true;
        }
        if (CrxId != other.CrxId) return false;
        return Equals(_unknownFields, other._unknownFields);
    }

    [DebuggerNonUserCode]
    public override int GetHashCode()
    {
        int hash = 1;
        if (CrxId.Length != 0) hash ^= CrxId.GetHashCode();
        if (_unknownFields != null)
        {
            hash ^= _unknownFields.GetHashCode();
        }
        return hash;
    }

    [DebuggerNonUserCode]
    public override string ToString()
    {
        return pb::JsonFormatter.ToDiagnosticString(this);
    }

    [DebuggerNonUserCode]
    public void WriteTo(pb::CodedOutputStream output)
    {
        if (CrxId.Length != 0)
        {
            output.WriteRawTag(10);
            output.WriteBytes(CrxId);
        }
        if (_unknownFields != null)
        {
            _unknownFields.WriteTo(output);
        }
    }

    [DebuggerNonUserCode]
    public int CalculateSize()
    {
        int size = 0;
        if (CrxId.Length != 0)
        {
            size += 1 + pb::CodedOutputStream.ComputeBytesSize(CrxId);
        }
        if (_unknownFields != null)
        {
            size += _unknownFields.CalculateSize();
        }
        return size;
    }

    [DebuggerNonUserCode]
    public void MergeFrom(SignedData other)
    {
        if (other == null)
        {
            return;
        }
        if (other.CrxId.Length != 0)
        {
            CrxId = other.CrxId;
        }
        _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
    }

    [DebuggerNonUserCode]
    public void MergeFrom(pb::CodedInputStream input)
    {
        uint tag;
        while ((tag = input.ReadTag()) != 0)
        {
            switch (tag)
            {
                default:
                    _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
                    break;
                case 10:
                    {
                        CrxId = input.ReadBytes();
                        break;
                    }
            }
        }
    }

}
#endregion
#endregion Designer generated code

You have a lot more here than I started with when I did this. Using this code and a Registry writer to add your details to registry you can have a Chrome Extension deployment/installation internal tool.

like image 135
CodeAngry Avatar answered Sep 29 '22 09:09

CodeAngry


You cannot distribute an extension witch isn't in the Chrome Extension Store. According to the official chrome docs, every extension distributed either from the chrome extension store or outside of it must be uploaded to the chrome extension store. If you want to distribute your extension outside of the store, after you have uploaded it, I think you should create a script that modifies the register and it will install it for you.

like image 29
Leandro Farias Avatar answered Sep 29 '22 08:09

Leandro Farias