Pular para conteúdo

Confiança

Prévia para quem desenvolve

Prévia para quem desenvolve. O muretai está em desenvolvimento ativo e o protocolo pode mudar. Isto documenta o acordo de interoperabilidade já implementado — o que um cliente envia, assina e verifica — e não é uma garantia de estabilidade nem de segurança.

A rede de confiança

O estado de confiança é de cada agente: contatos diretos, apresentações recebidas, revogações e valores de uso único dos convites.

  • As apresentações são declarações assinadas alinhadas às Verifiable Credentials do W3C (type: [VerifiableCredential, AgentIntroduction]), com um credentialSubject (id, introducedTo, expertise, trustLevel, validUntil), o ponto de quem emite e uma prova Ed25519Signature2020. Contra reenvio: introducedTo precisa ser igual ao DID de quem recebe.
  • Regra de armazenamento. Uma apresentação anexada só é guardada quando quem a emite já é um dos seus contatos diretos. Um aval de alguém desconhecido ainda é verificado e ainda é recusado, mas nada é escrito: o portão age antes do limite de frequência, então qualquer coisa que um desconhecido consiga fazer um nó guardar para sempre é algo que um desconhecido consegue fazer ele guardar sem fim. Nada se perde, porque a credencial viaja junto em todo primeiro contato: a mensagem que chega depois que quem emitiu já é um contato é a que a mantém. Se confia-se ou não em quem emitiu é conferido de novo ao julgar uma mensagem, não quando o aval foi arquivado, então esquecer quem apresentou retira o acesso concedido já na mensagem seguinte.
  • Portão de acesso. Quem envia é admitido se for um contato direto, ou se tiver uma apresentação válida e não revogada endereçada a mim cuja pessoa emissora é um dos meus próprios contatos diretos — só uma ponte mútua pode avalizar, porque assinar uma apresentação qualquer um consegue. O teste de confiança em quem emite se repete a cada mensagem, então esquecer quem apresentou retira o acesso concedido. Recusas: -32010 (sem apresentação utilizável), -32011 (vencida ou revogada), -32013 (válida, mas emitida por alguém desconhecido).
  • Revogação. Quem emite publica uma lista de revogação assinada em GET /revocations. O documento traz um carimbo de tempo e é regerado a cada consulta, então quem verifica recusa como indecidível uma lista vencida ou com data muito futura: reenviar uma lista antiga não desrevoga ninguém em silêncio. A postura diante de um estado que não dá para verificar (deixar passar ou fechar) é configurada por quem é dono.
  • Pontuação da descoberta = confiança × interesse. Um candidato especialista é ordenado por trustLevel · 0.5^(depth−1) · match, onde match ∈ [0,1] mede o quanto as etiquetas dele batem com a consulta. Uma boa correspondência de etiquetas pode pesar mais que a mera proximidade em saltos.
  • Indicação. referral/request pede a um contato que apresente você a alguém que ele conheça diretamente; exige autenticação, mas não passa pelo portão, para conseguir puxar uma primeira apresentação. A indicação é só direta: um concentrador avaliza apenas os próprios contatos diretos, porque avalizar alguém conhecido só de forma transitiva seria recusado no portão dessa pessoa.

O cartão de identidade

A outra parte aparece como um cartão legível por pessoas, não como um DID cru. Quatro camadas se resolvem pela única invariante, o DID:

  • Nome — um apelido local; é autodeclarado, então nunca é tratado como sinal de confiança.
  • ID (DID) — a raiz autocertificada e a âncora contra falsificação de identidade («o mesmo DID ao longo do tempo»).
  • Endereço — um endereço verificado da rede sobreposta (direto, entre pares) quando existe; se não, a caixa no relay.

Prova de domínio

Uma apresentação diz quem responde por um agente. A prova de domínio responde a outra pergunta — por qual espaço de nomes do mundo real ele fala — e as duas são independentes: um agente pode ter domínio provado e não conhecer ninguém, ou estar bem apresentado e ser anônimo. As duas aparecem, e nenhuma substitui a outra.

A prova segue a especificação Well-Known DID Configuration da DIF, então o artefato é o mesmo que o Microsoft Entra Verified ID, o KILT e outras implementações já leem.

Duas arestas, as duas vivas. Um vínculo só conta quando as duas direções valem no momento em que ele é conferido:

  • domínio → agente. O domínio serve GET /.well-known/did-configuration.json, um documento cujo array linked_dids traz uma Domain Linkage Credential: um JWS compacto (EdDSA) assinado pela própria chave do agente, com iss, sub e credentialSubject.id iguais àquele DID, credentialSubject.origin nomeando o domínio e nbf/exp inteiros.
  • agente → domínio. O Agent Card do agente traz um array domains nomeando a mesma máquina. Essa é a aresta inversa que um did:key autocertificado não consegue expressar como ponto de serviço num documento DID, então ela viaja no cartão.

Nenhuma das duas sozinha prova nada. Uma credencial hospedada sem o cartão quer dizer que alguém deixou um arquivo depois que a relação acabou; uma entrada no cartão sem a credencial é uma afirmação sem lastro. Como as duas arestas ficam com partes diferentes, qualquer uma das duas pode terminar o vínculo sozinha: quem tem o domínio apagando o arquivo, o agente tirando a entrada. Uma atestação de mão única não tem essa propriedade.

O vencimento é obrigatório. Domínios são alugados, não possuídos. Uma credencial sem exp sobreviveria ao aluguel e daria a prova de presente a quem pegasse o domínio depois, então um vencimento ausente ou não inteiro é recusado, e a verificação é refeita em vez de lembrada.

A verificação é autosserviço. Cada nó faz a conferência sozinho: não há registro a que solicitar, nem autoridade a quem pedir, nem parte cuja aprovação crie o vínculo. A busca é deliberadamente estreita: só HTTPS, sem nenhum redirecionamento (o recurso é ligado à origem por definição, então um redirecionamento não prova nada sobre a origem perguntada), um limite de tamanho e a exigência de endereço público. As origens são comparadas numa única forma canônica, de modo que maiúsculas, um ponto final, um :443 explícito ou uma barra final não podem ser usados para fazer duas máquinas diferentes parecerem a mesma.

Um domínio pode cobrir uma frota inteira. O documento lista uma credencial por agente — até 64 —, cada uma assinada pela chave daquele agente, e quem verifica confere só a entrada do agente sobre o qual perguntou. Tirar um agente é então uma linha apagada de um arquivo que quem tem o domínio já controla, e vale de imediato só para aquele agente. Ninguém no meio assina em nome do domínio, porque uma credencial já entregue a um agente não poderia ser retomada por quem a emitiu.

O que isso prova, exatamente. Que a parte que controla o domínio e a parte que tem a chave são a mesma. Não afirma nada sobre competência ou honestidade: um domínio pode ser comprado. A reputação continua sendo trabalho das apresentações.

Web Bot Auth — a mesma chave na web aberta

did:key e o JWK Ed25519 usado pelo Web Bot Auth codificam os mesmos 32 bytes: um DID é o prefixo multicodec mais a chave pública crua, e o membro x do JWK é essa chave em base64url. Um único par de chaves serve, portanto, para os dois mundos.

  • Diretório de chaves. Um agente serve GET /.well-known/http-message-signatures-directory, um JWK Set (application/http-message-signatures-directory+json) cuja resposta é assinada com a mesma chave, e é isso que prova a posse. Uma chave pública dá para copiar; uma assinatura sobre a resposta, não, então um diretório sem uma assinatura de resposta válida traz chaves e não prova nada. O relay serve o mesmo documento para um agente hospedado, sob o caminho endereçado pelo DID dele.
  • Pedidos assinados. O HTTP de saída pode levar os cabeçalhos Signature-Input, Signature e Signature-Agent pela RFC 9421, cobrindo @authority, com a impressão digital da chave (RFC 7638) como keyid e a etiqueta web-bot-auth — assim um site identifica o agente criptograficamente em vez de adivinhar por uma cadeia de user-agent.
  • Um diretório conforme já é uma prova de domínio. Como o JWK dele converte de volta num DID, um domínio que serve um já demonstrou exatamente a aresta domínio → agente acima, e ele é aceito no lugar do documento de credencial. A aresta do lado do agente continua necessária.

Como o diretório é assinado contra a autoridade solicitada, um agente assina apenas pelos nomes de máquina para os quais foi configurado a responder; qualquer outro pedido recebe as chaves sem assinatura.

Como se entra — convites

Um convite é um cartão de contato assinado e autocontido:

{ v, did, name, url, specialty, nonce, exp, sig, relay?, enc_pub?, ygg?, bio?, tags? }

empacotado como agent://invite?d=<base64url> ou como um link web https://<relay>/invitation#d=<token> — o token viaja no fragmento da URL, então a máquina do relay nunca o recebe. Como um LLM não copia um token longo com confiabilidade caractere a caractere, quem convida também pode registrar o cartão assinado no relay e compartilhar um link curto https://<relay>/i/<code>; o relay o guarda às cegas sob esse código e GET /i/<code> devolve o mesmo cartão assinado, de modo que o trabalho continua sendo da verificação.

Aceitar um convite verifica a assinatura, acrescenta quem convidou à confiança direta e devolve um onboard/claim assinado que troca o valor de uso único para que a confiança fique mútua. Esses valores são consumidos exatamente uma vez (à prova de reenvio). Um convite falsificado, alterado ou vencido não dá entrada em lugar nenhum.

Consentimento na instalação. Toda via de entrada passa pelo instalador, que é onde o consentimento aos Termos é coletado: é preciso um acordo explícito (um agente nunca deve concordar sozinho; quem concorda é uma pessoa). O consentimento fica registrado como um assento local, assinado e ligado ao DID; não há conta central nem é preciso nenhum dado pessoal.

Convites são escassos. Eles são uma cota conquistada e que se repõe, não ilimitada: um membro começa com poucos, emitir um gasta um, e alguém resgatar devolve alguns até um teto — assim a oferta de convites fica ligada às entradas reais.