Skip to content

Instantly share code, notes, and snippets.

@ChristopherA
Last active May 3, 2024 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChristopherA/dcf963c3849bc0d67b35c215efd15f86 to your computer and use it in GitHub Desktop.
Save ChristopherA/dcf963c3849bc0d67b35c215efd15f86 to your computer and use it in GitHub Desktop.
A Git Repo Root of Trust (A Proof-of-Concept & Work-in-Progress)

A Git Repo Root of Trust (A Proof-of-Concept & Work-in-Progress)

by Christopher Allen, Principal Architect, Blockchain Commons

Purpose of the Repository "Inception" Process

  • Initialization of a Secure Repository: Establishing a new repository with a root of trust ensures all future changes and commits build on a secure and verified foundation.
    • NOTE: This initial commit relies solely on basic git and ssh-keygen tools, without additional code libraries or identity infrastructure.
  • Leverage DIDs: By utilizing Decentralized Identifiers (DIDs) instead of traditional email addresses in the author and committer fields, we enhance privacy and align with decentralized practices.
    • NOTE: The resulting initial commit identifier can serve as a unique identifier for the repository. A future "did:repo:git-commit-id" method could be created that allows a DID resolver to create a temporary DID Document to verify authentication keys.
  • Authentication of Commits: Signing commits with SSH keys ensures the authenticity of contributions, ensuring that only authorized modifications are made to the repository.
  • Future-Proofing Security: Setting up the structure for future commits to be authenticated via a specific file (repo-trust-manifest.env) allows for dynamic security policies that can evolve as the project grows.
    • NOTE: We plan to leverage the elision capabilities of the privacy-focused Gordian Envelope for the data store rather than a JSON object. Gordian Envelope also support encryption, compression, and threshold secret-sharing. If necessary, a JSON object can be dynamically generated by a DID Resolver.

Walkthrough of the Proof-of-Concept (using macOS Zsh Shell)

christophera@mnemosyne WIP % curl https://api.github.com/users/ChristopherA/ssh_signing_keys
[
  {
    "id": 184891,
    "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINTazxjqxsdh3Sv/7fxSTgr3qlCVByYoGDHHe428Fubp",
    "title": "eurynome.local/sign_id_25519_christophera@github.com",
    "created_at": "2023-10-26T06:28:34.882Z"
  },
  {
    "id": 219925,
    "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMU0/lvWurXvUcrvYNgfb02Ska0qpwC/yv22dvDIxxzh",
    "title": "kymindis.local/sign_id_ed25519_christophera@github 2024-01-04",
    "created_at": "2024-01-04T20:13:55.503Z"
  },
  {
    "id": 233116,
    "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S",
    "title": "sign_id_ed25519-mnemosyne.local-christophera@github_2024_02_26",
    "created_at": "2024-01-26T21:35:28.362Z"
  }
]
christophera@mnemosyne WIP % mkdir test
christophera@mnemosyne test % cd test
christophera@mnemosyne test % git init
Initialized empty Git repository in ~/WIP/test/.git/
christophera@mnemosyne test % GIT_AUTHOR_NAME='@ChristopherA' \
GIT_AUTHOR_EMAIL='did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614?serviceEndpoint=https%3A%2F%2Fgithub.com%2FChristopherA%2FChristopherA' \
GIT_COMMITTER_NAME='repo-inception-role' \
GIT_COMMITTER_EMAIL='did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614?roleauth=repo-inception-role' \
git commit --allow-empty --no-edit --gpg-sign=~/.ssh/sign_id_ed25519-mnemosyne.local-christophera@github_2024_01_26 \
-m "Initialize repository and establish root of trust" \
-m "Repo Inception Public Key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S" \
-m "This key authenticates initial commits to this repo." \
-m "Future commits may be authenticated via ~/repo-trust-manifest.env" \
-m "which may be added to this repo in a commit signed by this key, thereby superseding its authority."
Enter passphrase: 
[main (root-commit) deedb33] Initialize repository and establish root of trust
 Author: @ChristopherA <did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614?serviceEndpoint=https%3A%2F%2Fgithub.com%2FChristopherA%2FChristopherA>
christophera@mnemosyne test % git rev-list --all
deedb3380e3e75266a009ee43b1dec54619f1b0f
christophera@mnemosyne test % git cat-file -p deedb3380e3e75266a009ee43b1dec54619f1b0f
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
author @ChristopherA <did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614?serviceEndpoint=https%3A%2F%2Fgithub.com%2FChristopherA%2FChristopherA> 1713979407 -0700
committer repo-inception-role <did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614?roleauth=repo-inception-role> 1713979407 -0700
gpgsig -----BEGIN SSH SIGNATURE-----
 U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgLY72f0jtErUNe+d3v54phP7QKv
 VsIm903+l2RvvrblIAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
 AAAAQCWJaPhFvKu6UEXFNvfG1SLx8NXnJ3P85mKwMDnLzmLYiHKEiywin+ew7Ow0KbxBOc
 joFiQeCbg4hdujaiNH+Qc=
 -----END SSH SIGNATURE-----

Initialize repository and establish root of trust

Repo Inception Public Key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S

This key authenticates initial commits to this repo.

Future commits may be authenticated via /repo-trust-manifest.env

which may be added to this repo in a commit signed by this key, thereby superseding its authorityy.
christophera@mnemosyne test %

Given this example, a unique DID for this resository could be did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f.

If a DID Resolver was asked to create a DID Document for this DID, solely based on the information in the inception commit, it could be created dynamically something along the lines of (NOTE: this example actually non-conforming with the standard and is missing a real W3C schema). Fixes TBW):

{
  "@context": "https://www.w3.org/ns/did/v1",
  "id": "did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f",
  "verificationMethod": [
    {
      "id": "did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f#ssh-key-1",
      "type": "SshPublicKey",
     "controller": "did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614?serviceEndpoint=https%3A%2F%2Fgithub.com%2FChristopherA%2FChristopherA"
      "publicKeySsh": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S"
    }
  ],
  "authentication": [
    {
      "id": "did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f#ssh-key-1",
      "type": "SshPublicKey",
      "controller": "did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614?serviceEndpoint=https%3A%2F%2Fgithub.com%2FChristopherA%2FChristopherA"
      "publicKeySsh": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S",
      "proofPurpose": "authenticationCommitOnly"  // Indicating restricted use specifically for commit authentication
    }
  ]
}

Walkthrough Details

This step-by-step walkthrough demonstrates a proof-of-concept for establishing a secure, verifiable digital workspace using cryptographic signatures and decentralized identity (DID) concepts. Here’s why and how this is done:

  • Retreival of SSH Public Keys: Retrieving current public SSH signing keys via curl from GitHub’s API endpoint.
  • Repository Setup: Creating a directory and initializing a Git repository within it forms the basic workspace for the project.
  • Commit Configuration: By setting Git author and committer identities to DIDs and signing the commit with an SSH key, the repository’s root commit is securely established. This includes:
    • Using a DID as the author and committer identifiers to point to a service endpoint, enhancing the traceability and verification of identity of the entity that initially created the repository (its "inception").
      • Note: The author could be "anonymous" or "pseudoanonymous" (aka revocable anonymous).
      • Note: The endpoint could be "*" which means it refers solely to information available in this commit, or in subsequent commits, in this repo's /repo-trust-manifest.env, a privacy-focused elidable data store.
    • Signing the initial commit with an SSH key to authenticate the inception of the repository.
  • Commit Message Content: The commit messages detail the security setup, the role of the public key, and the future application of a trust manifest file.
  • Review and Verification: Commands like git rev-list and git cat-file are used to verify the commit ID and review the commit details, ensuring everything is recorded as intended.

Verification of Inception Commit

  • Initial Verification: This involves confirming that the commit ID and the contents of the initial commit (such as the SSH public key) match the expected values and configurations.
  • Ongoing Verification: Continuous verification of repository integrity, including the optional addition of a repo-trust-manifest.env manifest.

Implications and Advantages

This methodology not only secures the initial repository setup with decentralized credentials but also prepares the project for a scalable and secure management system. By integrating DIDs and SSH key signatures, the repository adheres to modern security practices that are crucial for projects involving sensitive or significant digital assets. This approach illustrates the application of decentralized identifier standards for repositories, making them more resilient and adaptable to evolving security requirements.

Additional Points

  • Utilization of Existing Infrastructure: This technique leverages existing Git code and infrastructure, such as GitHub and GitLab, which support SSH-based Git commit signing and provide APIs for publishing the public signing keys of contributor accounts.
  • Distributed Nature of Git: While GitHub and GitLab offer convenient platforms for repository hosting, the distributed nature of Git allows users to utilize this methodology independently of these services, providing flexibility and control over the repository management and security.

Security Considerations

Use of SHA-1 in Git Commits

SHA-1 has been found to be vulnerable to collision attacks, which could undermine the security integrity of the commit hashes. While the use of SHA-1 for the first "inception" commits does not provide robust security against such attacks, it is important to note that the security of a Git repository as a whole typically increases with each additional commit. This is because each commit hash incorporates the hash of the previous commit, forming a chain. As a result, altering any single commit would require recalculating the hashes of all subsequent commits, which compounds the computational difficulty of an attack, thereby enhancing security over time.

However, users should be aware of these vulnerabilities, especially for critical security-related repositories. It is advisable to consider mechanisms that add additional layers of security (such as in repo-trust-manifest.env) could provide better assurance of the integrity and authorship of changes.

Enhancing Repository Security with /repo-trust-manifest.env

After securely establishing a repository with an inception commit, the inception key alone can initially authenticate subsequent commits. However, as more contributors join, it's crucial to dynamically manage ongoing security and authentication protocols.

This requirement is met by introducing a trust manifest, represented by the /repo-trust-manifest.env. This manifest serves as a robust framework for enhancing the repository's initial trust policy. Added in a commit signed by the inception key, it employs the sophisticated Gordian Envelope format to expand and adapt the trust policy to evolving security needs. This ensures that all subsequent commits adhere to the defined trust policies and facilitates the inclusion of a broader range of cryptographic keys and advanced trust policies in the future.

Understanding the /repo-trust-manifest.env Post-Inception

Structure and Composition

The /repo-trust-manifest.env is structured as a Gordian Envelope, which not only encapsulates trust policies but also aligns with decentralized identity principles. Here is what a typical manifest might look like soley based on the inception commit details:

"did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f" [
    'isA': "TrustPolicy"
    'authenticates': "Commits"
    'verificationMethod': [
        {
            'id': "did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f#ssh-key-1"
            'type': "SshPublicKey"
            'use': "authenticationCommitOnly"
            'controller': "did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614" [
                'serviceEndpoint': "https://github.com/ChristopherA/ChristopherA"
            ]
            'publicKeySsh': "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S"
            'validFrom': "2024-01-26T21:35:28.362Z"
            'role': "repo-inception-role"
            'description': "This key is used solely for authenticating initial commits to this repository."
        }
    ]
]

Key Components Explained

  • 'id' and 'type': Aa unique identifier coupled with its type (SSH public key), which connects the key to a specific function and role within the repository's security framework.
  • 'isA': "TrustPolicy": Specifies that the manifest functions as a policy governing trust within the repository, detailing the protocols for managing repository interactions and ensuring compliance with security measures.
  • 'authenticates': "Commits": Indicates that the primary function of the policy is to authenticate commits made to the repository, ensuring they meet the established security criteria.
  • 'verificationMethod': This section details the methods and criteria for verifying the authenticity of commits, including:
    • Structured as an array to accommodate future contributors.
    • 'id' and 'type': Unique identifier for the verification method along with its type (SSH public key).
    • 'use': Specifies the purpose of the key, set to "authenticationCommitOnly" to ensure that the keys are used strictly for commit authentication, thereby safeguarding the repository from other unauthorized changes.
    • 'controller' and 'serviceEndpoint': Provides information about who controls the key, along with a DID URL where more information about the controller can be found. This information enhances transparency and allows for traceability of actions within the repository.
    • 'publicKeySsh': Lists the actual public SSH key used by the contributor for authentication. This key are central to the SSH-based authentication mechanism employed by the repository.
    • 'validFrom': Indicates the date from which the key is valid, establishing a timeline for when the key is authorized for use within the repository's operations.
    • 'role' and 'description': Provides additional context about the role associated the key and a brief description of its intended use. This detail clarifies the responsibilities and expected behaviors associated any keys, ensuring all contributors understand their limitations and permissions.

Adding a New Contributor to the /repo-trust-manifest.env

As the repository grows and additional contributors join, it's crucial to dynamically manage ongoing security and authentication protocols. This process ensures that new team members are authorized to make commits in a secure and controlled manner, aligning with the existing trust policies.

Steps to Include an Additional Contributor

  1. Generate or Obtain the Contributor’s Public SSH Key: Before adding a new contributor to the manifest, ensure that you have their public SSH key, which will be used to authenticate their commits.

  2. Update the Trust Manifest: Integrate the new contributor's key into the existing trust manifest by adding it to the verificationMethod array. This array should include details for each contributor’s SSH key. Each key must be uniquely identified and have its role within the repository clearly defined. This approach ensures that all keys are managed under the same policy framework, maintaining consistency and clarity in the repository's trust policy.

Here’s how the updated manifest might look after adding a second contributor:

"did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f" [
    'isA': "TrustPolicy"
    'authenticates': "Commits"
    'verificationMethod': [
        {
            'id': "did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f#ssh-key-1"
            'type': "SshPublicKey"
            'use': "authenticationCommitOnly"
            'controller': "did:repo:dbe44e2f99347b403b8b649605dd718bf5a69614" [
                'serviceEndpoint': "https://github.com/ChristopherA/ChristopherA"
            ]
            'publicKeySsh': "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S"
            'validFrom': "2024-01-26T21:35:28.362Z"
            'role': "repo-inception-role"
            'description': "This key is used solely for authenticating initial commits to this repository."
        },
        {
            'id': "did:repo:deedb3380e3e75266a009ee43b1dec54619f1b0f#ssh-key-2"
            'type': "SshPublicKey"
            'use': "authenticationCommitOnly"
            'controller': "did:repo:newContributor:newContributor" [
                'serviceEndpoint': "https://github.com/NewContributor"
            ]
            'publicKeySsh': "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFakeKey12345678FakeKeyV1234567ExampleKeyXyz"
            'validFrom': "2024-02-01T00:00:00Z"
            'role': "contributor"
            'description': "This key is used solely for authenticating commits made by the new contributor."
        }
    ]
]

Updated Trust Policy Explained

The updated trust policy in the /repo-trust-manifest.env now incorporates multiple contributors under a unified verification method, each detailed by their respective SSH keys. Here’s a breakdown of the additional components for the updated trust policy:

  • 'controller': There are now two. Each identifies who controls the key. Each are paired with a 'serviceEndpoint', providing a URL where more information about the controllers can be found. In the updated policy:

  • 'publicKeySsh': Lists the actual public SSH keys used for each contributor, which are essential for the SSH-based authentication mechanism.

  • 'validFrom': Indicates the date from which each key is valid, offering a timeline for its activation and use within the repository’s operations.

  • 'role' and 'description': Provides additional context about each key, defining the role associated with it and a brief description of its intended use. This detail helps to clarify expectations and responsibilities associated with each key:

    • The original key is designated for the "repo-inception-role", emphasizing its foundational importance.
    • The new key is assigned to a "contributor" role, highlighting its purpose for routine commit operations by the new contributor.

This structured approach to managing multiple SSH keys under a single verification method demonstrates a trust policy where each contributor’s role and permissions are explicitly defined and controlled. It transparently delineating the roles and responsibilities associated with each SSH key, facilitating better governance and more secure operations within the repository.

Clarifications and Further Development

This example and the procedures outlined for integrating additional contributors into the /repo-trust-manifest.env represent a proof-of-concept only. This early draft is intended for illustrative purposes to demonstrate how a trust policy might be initially structured within a repository using the Gordian Envelope format.

  • Complexity and Real Implementations: In practice, trust policies within a repository are likely to be much more sophisticated. The simple example of adding a contributor's SSH key does not encompass the full breadth of security considerations necessary in a production environment.
  • Role and Permission Specifications: Detailed policies regarding roles, permissions, and conditions under which contributors can interact with the repository need to be clearly defined and implemented.
  • Future Developments: The implementation of various trust policies using Gordian Envelope is a topic for future development. This includes exploring how different levels of access and control can be dynamically managed and securely integrated into the repository’s governance structure.

Strategic Advantages of /repo-trust-manifest.env

  • Extensible Authentication Mechanisms: This manifest can incorporate additional SSH signing keys, not only for other developers, but to uphold key separation best practices across varied development environments. Additionally, non-SSH signing keys, such as group threshold keys, and other signature formats, like aggregated signatures, can be supported. The manifest clearly delineates the conditions under which these keys are authorized, establishing a structured and secure framework to verify future commits.
  • Privacy and Security Through Elision and Encryption: Leveraging the Gordian Envelope format, the manifest supports either the elision or encryption of sensitive data. This feature is crucial for maintaining the confidentiality of sensitive information while enabling verification without requiring full disclosure. This protects not only the personal data of developers but also the confidential and competitive information of stakeholders. If additional verification of elided data is required, various proofs of inclusion can be provided.
  • Adaptive Security Dynamics: The manifest dynamically adapts to changing project requirements, accommodating shifts in team structure, project direction, and security levels. This adaptability ensures the repository's security measures remain effective and appropriate without the need for constant foundational overhauls.
  • Decentralized Trust Management: By detailing complex, graph-based trust relationships among keys and roles, the manifest decentralizes trust management. This approach enhances the resilience of the repository's security framework and distributes authority, thereby minimizing single points of failure and enhancing overall security robustness.
  • Comprehensive Security Assertions: The manifest may include a range of other security assertions., including security reviews, usage logs, and metadata. These components provide a detailed view of the repository’s security landscape, aid in vulnerability assessments, and streamline the management of repository configurations.
  • Enhanced Interoperability: The manifest facilitates diverse operational functions across systems, facilitating functions such as access control, audit logging, and compliance tracking. This capability promotes interoperability and functional synergy across different systems and platforms.

Related Code

Related Works

@ChristopherA
Copy link
Author

ChristopherA commented May 3, 2024

There is some confusion in language between "auth", "authenticate", "sign", "authorize", etc. I'm playing around with:

git commit --allow-empty --no-edit --gpg-sign=~/.ssh/sign_id_ed25519-mnemosyne.local-christophera@github_2024_01_26 \
-m "Initialize repository and establish root of trust" \
-m "Repo Inception Public Key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC2O9n9I7RK1DXvnd7+eKYT+0Cr1bCJvdN/pdkb7625S" \
-m "This key certifies future commits' integrity and origin. Additional keys \
can be authorized to certify commits via the creation of an ./_allowed_commit_signers \
file. This file must initially be signed by the inception key, granting these keys \
the authority to certify commits, including the potential to remove the authority \
of the inception key. Once established, any changes to ./_allowed_commit_signers \
must be certified by one of the previously approved signers."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment