# ITMS-90034: rezolvă „Missing or invalid signature”

> ITMS-90034: build-ul tău nu e semnat cu un certificat de distribuție valid. Citește-i semnătura cu codesign, apoi refă un build store cu EAS.

Pagina originală: [ITMS-90034: rezolvă „Missing or invalid signature”](https://devoria.fr/ro/blog/itms-90034-missing-invalid-signature)
Autor: [Mehdi Azizi](https://devoria.fr/ro/mehdi-azizi)
Publicare: 2026-11-04
Ultima revizuire a conținutului: 2026-11-04


ITMS-90034 apare când trimiți build-ul la App Store Connect. Îți spune că aplicația ta, sau una dintre componentele ei, nu e semnată cu un certificat de trimitere Apple, adică un certificat de distribuție valid. **Soluția: găsești ce bundle e semnat greșit și de ce, apoi refaci un build semnat pentru App Store.**

Ghidul ăsta rămâne concentrat pe eroare. Dacă termenii certificat și profil nu-ți sunt clari, citește mai întâi [certificatul de dezvoltator iOS și provisioning profile](https://devoria.fr/ro/blog/certificat-dezvoltator-ios-provisioning-profile-expo). Aici găsești mesajul de citit, un arbore de decizie, comenzile care îți inspectează IPA-ul și rezolvarea cu credențialele gestionate de EAS. Pentru partea de EAS, am citit codul din EAS CLI 24.10.0 care alege certificatul.

## Ce înseamnă eroarea ITMS-90034?

Iată forma ei clasică, cu nume de exemplu:

> ITMS-90034: Missing or invalid signature. The bundle 'com.example.myapp' at bundle path 'Payload/MyApp.app' is not signed using an Apple submission certificate.

În 2026, pe forumul Apple, apare și sub forma „Validation failed (409) Missing or invalid signature”, urmată de același text și de „(ID: 90034)”.

„Certificatul de trimitere” e certificatul de distribuție. [Ajutorul Apple despre certificate](https://developer.apple.com/help/account/certificates/certificates-overview) o spune clar: certificatele de dezvoltare servesc la rularea aplicației pe dispozitivele tale, cele de distribuție la distribuirea ei sau la trimiterea ei la App Store Connect.

**Citește calea menționată: ea arată bundle-ul vinovat.** `Payload/MyApp.app` se referă la aplicația propriu-zisă. O cale care se termină în `.appex` se referă la o extensie, cum ar fi un widget. O cale în `.framework` se referă la o bibliotecă inclusă.

Nu e o respingere de la un reviewer. Validarea pică la trimitere sau în timpul procesării build-ului, înainte de TestFlight: build-ul ăsta nu va ajunge niciodată la testerii tăi.

## Arborele de decizie: de la mesaj la rezolvare

Fiecare rând corespunde unui indiciu pe care îl citești în mesaj, în comenzile din secțiunea următoare sau în logurile EAS. Ia-le în ordine: primul care se potrivește îți dă pista.

| Ce observi                 | Cauză probabilă         | Rezolvare                  |
| -------------------------- | ----------------------- | -------------------------- |
| Cale în `.appex`           | Extensie semnată greșit | Declară extensia           |
| `Signature=adhoc`          | Build nesemnat          | Build cu profil store      |
| `Apple Development`        | Build de dezvoltare     | Build cu profil store      |
| `ProvisionedDevices` citit | Build intern (ad hoc)   | Build cu profil store      |
| `sealed resource`          | IPA modificat ulterior  | Refă build-ul              |
| EAS: „no longer valid”     | Certificat revocat      | Certificat nou             |
| Totul e valid              | Incident la Apple       | Retrimite, apoi raportează |

## Inspectează-ți IPA-ul în patru comenzi

Descarcă IPA-ul de pe pagina build-ului de pe expo.dev, apoi deschide un terminal pe Mac.

**1. Cine a semnat aplicația?**

```bash
unzip -q MyApp.ipa -d ipa
codesign -dv --verbose=4 ipa/Payload/*.app 2>&1 | grep -E "^(Identifier|Authority|Signature|TeamIdentifier)="
```

`codesign` scrie pe ieșirea de eroare, de aici `2>&1`. Conform [notei tehnice TN3161 de la Apple](https://developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates), fiecare linie `Authority` e o verigă din lanțul de încredere. Prima trebuie să înceapă cu `Apple Distribution:` sau `iPhone Distribution:`, urmată de numele echipei tale. A doua etichetă e cea a vechiului tip iOS Distribution: după codul său, EAS CLI 24.10.0 încă mai creează certificate de tipul ăsta. Dacă vezi `Apple Development:`, e un build de dezvoltare. Dacă vezi `Signature=adhoc` fără nicio linie `Authority`, binarul nu e semnat de niciun certificat.

**2. A fost modificată aplicația după semnare?**

```bash
codesign --verify --deep --strict -vv ipa/Payload/*.app
```

Vrei să vezi `valid on disk`, apoi `satisfies its Designated Requirement`. TN3161 precizează ce garantează verificarea asta: toate fișierele așteptate sunt acolo, niciunul n-a fost adăugat, niciunul n-a fost modificat. Pe un bundle de test pe care l-am semnat și apoi l-am retușat, comanda răspunde `a sealed resource is missing or invalid`, apoi `file modified:` urmat de fișierul schimbat. Opțiunea `--deep` servește aici la verificare, niciodată la semnare: pe forumul Apple, un inginer din echipa de suport o descurajează pentru semnare.

**3. Ce profil e inclus?**

```bash
security cms -D -i ipa/Payload/*.app/embedded.mobileprovision -o profile.plist
plutil -extract ProvisionedDevices xml1 -o - profile.plist
plutil -extract ExpirationDate raw profile.plist
```

Sunt comenzile din [nota TN3125 despre profiluri](https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles). Un profil App Store nu conține nicio listă de dispozitive: a doua linie trebuie să răspundă `Could not extract value`. Dacă afișează identificatori de dispozitive, e un profil ad hoc, cel al unui build intern. A treia îți dă data de expirare a profilului.

**4. Extensiile și framework-urile sunt semnate la fel?**

```bash
find ipa/Payload/*.app \( -name "*.appex" -o -name "*.framework" \) \
  -exec sh -c 'echo "$1"; codesign -dvv "$1" 2>&1 | grep -m1 "^Authority="' _ {} \;
```

Fiecare componentă trebuie să afișeze aceeași linie `Authority` ca aplicația. Dacă una diferă, pe ea o menționează mesajul.

Dacă vrei să verifici înainte de trimitere, TN3161 recomandă `altool`, aceeași verificare ca butonul Validate App din Xcode. Are nevoie de o cheie API App Store Connect, al cărei fișier `AuthKey_<KEY_ID>.p8` se pune în `~/.appstoreconnect/private_keys`:

```bash
xcrun altool --validate-app -f MyApp.ipa -t ios --api-key <KEY_ID> --api-issuer <ISSUER_ID>
```

## Rezolvarea cu EAS, cauză cu cauză

### Un build intern sau de dezvoltare trimis la Apple

Conform [documentației Expo despre eas.json](https://docs.expo.dev/build/eas-json/), build-urile cu `"distribution": "internal"` nu sunt semnate pentru store-uri: folosesc un profil ad hoc. Doar un profil cu distribuție `store`, valoarea implicită, produce un build care poate fi trimis. **Cel mai sigur e să trimiți build-ul pe care tocmai l-ai construit, fără să-l alegi de mână**:

```bash
eas build --platform ios --profile production --auto-submit
```

Dacă folosești `eas submit --path`, verifică dacă fișierul e chiar ultimul tău build store. Pe forumul Apple, o echipă a descoperit că unealta ei de trimitere retrimitea de fiecare dată un IPA vechi, versionat în git.

### O extensie uitată

Fiecare extensie e un bundle separat, cu identificatorul și profilul ei. Într-un proiect Expo cu generare nativă, [pagina Expo despre extensiile iOS](https://docs.expo.dev/build-reference/app-extensions/) cere să le declari în `extra.eas.build.experimental.ios.appExtensions`. Așa EAS CLI le cunoaște înainte de build și le creează sau le validează credențialele. Majoritatea bibliotecilor care adaugă o extensie scriu declarația asta pentru tine, prin plugin-ul lor.

Solys, alarma mea cu mini-jocuri, include patru extensii: un widget și trei extensii Screen Time. Toate patru sunt declarate în configurație, iar EAS are un profil pentru fiecare. **O extensie adăugată de mână în Xcode, fără declarația asta, e candidatul ideal** pentru o cale în `.appex` în mesaj.

### Un certificat revocat sau expirat

[Pagina Apple despre certificate](https://developer.apple.com/support/certificates/) e clară: nu mai poți trimite un build semnat cu un certificat expirat sau revocat. Un build deja trimis, dar încă neînaintat la review, poate chiar să treacă în Invalid Binary dacă certificatul lui a fost revocat.

Codul din EAS CLI 24.10.0 arată când trece cazul ăsta neobservat:

- **Build interactiv, conectat la Apple**: EAS își compară certificatul cu cele încă valide la Apple. Dacă nu mai e acolo, afișează „Current distribution certificate is no longer valid in Apple Dev Portal” și îți propune să alegi sau să creezi unul.
- **Build interactiv, fără conectare**: EAS verifică doar datele și te avertizează că sare peste validarea la Apple.
- **Build neinteractiv, în integrare continuă**: EAS afișează „Distribution Certificate is not validated for non-interactive builds” și semnează oricum.

**În integrare continuă, EAS nu reverifică certificatul în sine: o revocare se poate vedea abia la trimitere.** Rezolvarea: pornește un build interactiv conectat la contul tău Apple, sau treci prin `eas credentials --platform ios`, meniul Build Credentials, apoi „Distribution Certificate: Add a new one to your account”. Profilurile care conțineau vechiul certificat devin invalide: EAS le verifică la următorul build și le reface. Limitele Apple privind numărul de certificate sunt detaliate în [ghidul despre certificatul de dezvoltator iOS](https://devoria.fr/ro/blog/certificat-dezvoltator-ios-provisioning-profile-expo).

### Un binar modificat după semnare

Semnătura sigilează codul, resursele și metadatele prin hash-uri, cum explică [nota TN3126 de la Apple](https://developer.apple.com/documentation/technotes/tn3126-inside-code-signing-hashes). Dacă dezarhivezi IPA-ul ca să schimbi un fișier și apoi îl rearhivezi, rupi sigiliul. **Fă modificarea în configurație, apoi refă build-ul.** Nu retușa niciodată IPA-ul produs de EAS.

Aceeași logică pentru cod pus în locul greșit, de exemplu într-o arhivă `.zip`: App Store nu-l poate re-semna. Apple descrie locațiile permise în pagina despre [conținutul unui bundle](https://developer.apple.com/documentation/bundleresources/placing-content-in-a-bundle).

### Credențiale locale

Dacă profilul tău EAS folosește `"credentialsSource": "local"`, fișierul `credentials.json` indică un certificat `.p12` și un profil `.mobileprovision`. Verifică profilul cu comenzile de la pasul 3: trebuie să fie de tip App Store și să conțină certificatul tău de distribuție actual. Și ține fișierele astea în afara repository-ului, ca pe [cheile API ale unei aplicații Expo](https://devoria.fr/ro/blog/cheie-api-secreta-aplicatie-expo).

### Când totul e valid

Mai rămâne un caz frustrant. Pe forumul Apple, unii dezvoltatori văd eroarea dispărând când retrimit același build, fără să schimbe nimic. În august și septembrie 2026, două thread-uri descriu opusul: certificat și profil noi, semnătură verificată, eșec persistent. Într-unul dintre ele, un inginer Apple recomandă un raport de bug cu IPA-ul, analiza semnăturii și logurile din Transporter, apoi un contact cu App Store Connect.

Așa că retrimite o dată cu un număr de build nou. Dacă eroarea revine deși cele patru comenzi ies curate, raportează-o la Apple cu elementele astea. **Nu-ți revoca certificatul din reflex**: nu rezolvă nimic în plus și îți invalidează profilurile.

## Trimite-ți build-ul fără surprize neplăcute

O semnătură se verifică în două minute înainte de trimitere. Celelalte verificări automate cer aceeași rigoare, cum ar fi [ITMS-90725](https://devoria.fr/ro/blog/itms-90725-sdk-version-issue-expo) pentru versiunea de Xcode sau [ITMS-90683](https://devoria.fr/ro/blog/itms-90683-missing-purpose-string-expo) pentru textele de permisiune. Tot parcursul de la build la trimitere, fără Mac, îl găsești în [publică o aplicație iOS fără Mac](https://devoria.fr/ro/blog/publicare-aplicatie-ios-fara-mac-expo-eas).

Respingerile de la un reviewer cer mai multă detașare: pașii sunt pe pagina [aplicație respinsă de Apple](https://devoria.fr/ro/expertise/aplicatie-respinsa-de-apple), iar motivele cele mai frecvente sunt în [de ce respinge Apple o aplicație](https://devoria.fr/ro/blog/aplicatie-respinsa-apple-cazuri-reale).

Ca să-ți verifici dosarul înainte de trimitere, [Review Kit](https://devoria.fr/ro/kits/app-review) adună checklist-ul meu și skill-uri Claude Code care îți recitesc proiectul. Dacă trimiterea ți se blochează și vrei o privire umană, [rezervă o oră cu mine](https://devoria.fr/ro/coaching): reluăm proiectul tău pe video, pe ecranul tău. Iar dacă îți pregătești prima lansare, [fă-ți diagnosticul gratuit](https://devoria.fr/ro/diagnostic): îți pune pașii în ordine și îți trimite checklist-ul meu anti-respingere Apple.

## Întrebări frecvente

### ITMS-90034 e o respingere de la App Review?

Nu. E o validare automată făcută la trimiterea build-ului, înainte de TestFlight și înainte de orice review. Nimeni nu ți-a deschis aplicația: Apple a constatat doar că semnătura ei nu vine de la un certificat de distribuție valid.

### Trebuie să-mi revoc certificatul de distribuție ca să rezolv ITMS-90034?

Doar dacă e compromis sau deja invalid. Dacă revoci un certificat care funcționează, îți invalidezi profilurile fără să rezolvi cauza. Începe prin a citi semnătura IPA-ului cu `codesign`, apoi rezolvă ce indică arborele de decizie.

### Se poate rezolva ITMS-90034 cu un update la distanță?

Nu. Semnătura face parte din binar, iar build-ul respins nu va fi niciodată utilizabil. Trebuie să produci un binar nou, semnat corect, și să-l retrimiți.

### De ce menționează eroarea widget-ul meu și nu aplicația?

Pentru că widget-ul e un bundle separat, semnat cu propriul profil. Dacă nu e declarat în EAS sau a fost semnat altfel, pică toată trimiterea. Declară extensia în configurație și refă build-ul.

### Ce fac dacă codesign spune că totul e valid?

Verifică și profilul inclus și fiecare extensie. Dacă totul e curat, retrimite o dată cu un număr de build nou. Dacă eroarea persistă, trimite un raport la Apple cu IPA-ul, ieșirea din `codesign` și logurile de trimitere.


## Proiectul tău

[Review Kit](https://devoria.fr/ro/kits/app-review): Checklistul meu de review App Store, respingerile mele de la Apple rezolvate, checklistul pentru Google Play și trei skilluri Claude Code. 259 RON.

[iOS & Android Kit](https://devoria.fr/ro/kits/ios): Creează-ți aplicația de iPhone și Android cu Claude Code: codul de pornire al aplicațiilor mele, drumul până în store-uri și toate kiturile. 529 RON.

[Diagnostic: ce te desparte de aplicația ta de iPhone](https://devoria.fr/ro/diagnostic): 7 întrebări, 60 de secunde: afli ce te blochează de fapt să-ți publici aplicația de iPhone, traseul tău în 4 etape și kitul potrivit pentru tine.
