Shameless plug for https://smallstep.com/cli which makes the process of issuing and rolling certs (incl. client certs for mutual TLS) easy enough to be workable in a modern application.
Shameless plug for https://smallstep.com/cli which makes the process of issuing and rolling certs (incl. client certs for mutual TLS) easy enough to be workable in a modern application.
However, whether you're running your own or pulling public certs, you should go into any PKI setup assuming you'll need to change out all the certs at some point. If you're going private, make sure you have a mechanism to replace everything--yes, including that private root you just created!--in a safe and secure fashion. Preferably, that would include some manner of doing so that doesn't involve blowing everything up and leaving existing clients high and dry...but that's a business decision to make.
If you're going with public certs, you still have to make that assumption. I see too many developers still pinning trust to a single root CA like Let's Encrypt or GoDaddy and then being stuck when the CA in question is revoked, replaced, expires, or is booted out of public trust, or just because their business insists they use something different. The solution to this is a trust store, which you can make as minimal as you want to: pick two or three public root CAs, stick them in a blob, and tell your app to accept nothing else. That leaves you an out, for the next time the cert industry has a Symantec-like event and everyone has to get off that train right away, since you can move from one of those to another one without having to change anything in the app.
Then deploy your client apps with the certificate of your self signed root.
Assuming that your root is safe, no attacker will be able to generate a cert that will be accepted by your client.
Which part is confusing? Maybe I can try to clarify/give examples where helpful.
The attack on that latter system is that you as the client have no basis on which to trust that cert when its first presented. So an attacker who can intercept that first presentation of the certificate and replace it can MITM the traffic flow without you knowing. Worse, most devs "fix" that initial trust problem by telling the client not to validate the cert when its presented (because they wouldn't have any basis for doing that anyway), so an attacker is free to inject their own cert into the traffic at any time.
Using an actual private PKI hierarchy helps fix this: you create a root, and get your clients to trust only that root. Now you can issue your own certs, and an attacker can't MITM the traffic unless they can get their own cert from your CA. That's the same model as is used with commercial CAs: you're just operating the root of the chain yourself instead of paying someone else to do it.
Certificate Pinning is the solution you'd look to if you have a clients that cannot securely ship with root certificates/cannot pick the root certificates they will use to validate a certificate when initiating a TLS connection.
Edit: I should add that I am not a mobile developer, so I don't actually know if the 'bring your own root CA' method is supported by the corresponding TLS libraries. But I know that this is possible 'in general'
I call it trust-on-first-use because I didn't verify the initial signatures. Hmmm..