1 2 #include <petscwebclient.h> 3 4 static BIO *bio_err = NULL; 5 6 #define PASSWORD "password" 7 8 #if defined(PETSC_USE_SSL_CERTIFICATE) 9 static int password_cb(char *buf,int num, int rwflag,void *userdata) 10 { 11 if (num < strlen(PASSWORD)+1) return(0); 12 strcpy(buf,PASSWORD); 13 return(strlen(PASSWORD)); 14 } 15 #endif 16 17 static void sigpipe_handle(int x) 18 { 19 } 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PetscSSLInitializeContext" 23 /* 24 PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 25 26 If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with 27 28 $ ./CA.pl -newcert (using the passphrase of password) 29 $ cat newkey.pem newcert.pem > sslclient.pem 30 31 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 32 silly but it was all I could figure out. 33 34 */ 35 PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 36 { 37 SSL_CTX *ctx; 38 #if defined(PETSC_USE_SSL_CERTIFICATE) 39 char keyfile[PETSC_MAX_PATH_LEN]; 40 PetscBool exists; 41 PetscErrorCode ierr; 42 #endif 43 44 PetscFunctionBegin; 45 if (!bio_err){ 46 SSL_library_init(); 47 SSL_load_error_strings(); 48 bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 49 } 50 51 /* Set up a SIGPIPE handler */ 52 signal(SIGPIPE,sigpipe_handle); 53 54 ctx = SSL_CTX_new(SSLv23_method()); 55 56 #if defined(PETSC_USE_SSL_CERTIFICATE) 57 /* Locate keyfile */ 58 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 59 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 60 if (!exists) { 61 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 62 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 63 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 64 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 65 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 66 } 67 68 /* Load our keys and certificates*/ 69 if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 70 71 SSL_CTX_set_default_passwd_cb(ctx,password_cb); 72 if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 73 #endif 74 75 *octx = ctx; 76 PetscFunctionReturn(0); 77 } 78 79 #undef __FUNCT__ 80 #define __FUNCT__ "PetscSSLDestroyContext" 81 PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 82 { 83 PetscFunctionBegin; 84 SSL_CTX_free(ctx); 85 PetscFunctionReturn(0); 86 } 87 88 #undef __FUNCT__ 89 #define __FUNCT__ "PetscHTTPBuildRequest" 90 PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest) 91 { 92 char *request=0; 93 char contentlength[40],contenttype[80],*path,*host; 94 int r; 95 size_t request_len,len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0; 96 PetscErrorCode ierr; 97 PetscBool flg; 98 99 PetscFunctionBegin; 100 ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr); 101 ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr); 102 if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url); 103 *path = NULL; 104 ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 105 106 ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 107 ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 108 109 if (header) { 110 ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 111 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 112 } 113 114 ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 115 if (ctype) { 116 ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 117 ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 118 } 119 ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 120 ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 121 ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 122 ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 123 124 /* Now construct our HTTP request */ 125 request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 126 ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 127 ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 128 ierr = PetscStrcat(request," ");CHKERRQ(ierr); 129 ierr = PetscStrcat(request,path);CHKERRQ(ierr); 130 ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 131 ierr = PetscStrcat(request,host);CHKERRQ(ierr); 132 ierr = PetscFree(host);CHKERRQ(ierr); 133 ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 134 ierr = PetscStrcat(request,header);CHKERRQ(ierr); 135 if (ctype) { 136 ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 137 } 138 ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 139 ierr = PetscStrcat(request,body);CHKERRQ(ierr); 140 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 141 ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 142 143 *outrequest = request; 144 PetscFunctionReturn(0); 145 } 146 147 148 #undef __FUNCT__ 149 #define __FUNCT__ "PetscHTTPSRequest" 150 /* 151 PetscHTTPSRequest - Send a request to an HTTPS server 152 153 Input Parameters: 154 + type - either "POST" or "GET" 155 . url - URL of request host/path 156 . header - additional header information, may be NULL 157 . ctype - data type of body, for example application/json 158 . body - data to send to server 159 . ssl - obtained with PetscHTTPSConnect() 160 - buffsize - size of buffer 161 162 Output Parameter: 163 . buff - everything returned from server 164 */ 165 PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 166 { 167 char *request; 168 int r; 169 size_t request_len,len; 170 PetscErrorCode ierr; 171 172 PetscFunctionBegin; 173 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 174 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 175 176 r = SSL_write(ssl,request,(int)request_len); 177 switch (SSL_get_error(ssl,r)){ 178 case SSL_ERROR_NONE: 179 if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 180 break; 181 default: 182 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 183 } 184 185 /* Now read the server's response, assuming that it's terminated by a close */ 186 r = SSL_read(ssl,buff,(int)buffsize); 187 len = r; 188 switch (SSL_get_error(ssl,r)){ 189 case SSL_ERROR_NONE: 190 break; 191 case SSL_ERROR_ZERO_RETURN: 192 SSL_shutdown(ssl); /* ignore shutdown error message */ 193 break; 194 case SSL_ERROR_SYSCALL: 195 break; 196 default: 197 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 198 } 199 buff[len] = 0; /* null terminate string */ 200 ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 201 202 SSL_free(ssl); 203 ierr = PetscFree(request);CHKERRQ(ierr); 204 PetscFunctionReturn(0); 205 } 206 207 #undef __FUNCT__ 208 #define __FUNCT__ "PetscHTTPRequest" 209 /* 210 PetscHTTPRequest - Send a request to an HTTP server 211 212 Input Parameters: 213 + type - either "POST" or "GET" 214 . url - URL of request host/path 215 . header - additional header information, may be NULL 216 . ctype - data type of body, for example application/json 217 . body - data to send to server 218 . sock - obtained with PetscOpenSocket() 219 - buffsize - size of buffer 220 221 Output Parameter: 222 . buff - everything returned from server 223 */ 224 PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize) 225 { 226 char *request; 227 size_t request_len; 228 PetscErrorCode ierr; 229 230 PetscFunctionBegin; 231 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 232 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 233 234 ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr); 235 ierr = PetscFree(request);CHKERRQ(ierr); 236 PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR); 237 buff[buffsize-1] = 0; 238 ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr); 239 PetscFunctionReturn(0); 240 } 241 242 243 #undef __FUNCT__ 244 #define __FUNCT__ "PetscHTTPSConnect" 245 PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 246 { 247 BIO *sbio; 248 PetscErrorCode ierr; 249 250 PetscFunctionBegin; 251 /* Connect the TCP socket*/ 252 ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 253 254 /* Connect the SSL socket */ 255 *ssl = SSL_new(ctx); 256 sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 257 SSL_set_bio(*ssl,sbio,sbio); 258 if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 259 PetscFunctionReturn(0); 260 } 261 262